Quantcast
local CPF, OSF = ColorPickerFrame, OpacitySliderFrame

-- Make the color picker movable.
local mover = CreateFrame("Frame", nil, CPF)
mover:SetPoint("TOPLEFT", CPF, "TOP", -60, 0)
mover:SetPoint("BOTTOMRIGHT", CPF, "TOP", 60, -15)
mover:EnableMouse(true)
mover:SetScript("OnMouseDown", function() CPF:StartMoving() end)
mover:SetScript("OnMouseUp", function() CPF:StopMovingOrSizing() end)
CPF:SetUserPlaced(true)
CPF:EnableKeyboard(false)

local fauxHeader = CPF:CreateTexture(nil, "OVERLAY")
fauxHeader:SetTexture([[Interface\DialogFrame\UI-DialogBox-Header]])
fauxHeader:SetAllPoints(ColorPickerFrameHeader)

local hex = CreateFrame("EditBox", nil, CPF)
hex:SetAutoFocus(false)
hex:SetFontObject(ChatFontNormal)
hex:SetMaxLetters(6)
hex:SetJustifyH("CENTER")
hex:SetFrameLevel(10)
hex:SetPoint("TOPLEFT", CPF, "TOP", -40, 0)
hex:SetPoint("BOTTOMRIGHT", CPF, "TOP", 40, -15)
hex:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
hex:SetScript("OnEditFocusGained", function(self)
	self:HighlightText(0, self:GetNumLetters())
end)
hex:SetScript("OnEditFocusLost", function(self)
	self:HighlightText(self:GetNumLetters())
end)

-- Saturation slider.
local saturation = CreateFrame("Slider", "ColorTools_SatSlider", CPF, "OptionsSliderTemplate")
saturation:SetMinMaxValues(0, 1)
saturation:SetValueStep(.05)
saturation:SetOrientation("VERTICAL")
saturation:SetThumbTexture([[Interface\Buttons\UI-SliderBar-Button-Vertical]])
saturation:SetHeight(OSF:GetHeight())
saturation:SetWidth(OSF:GetWidth())
saturation:SetPoint("LEFT", OSF, "RIGHT", 5, 0)
_G["ColorTools_SatSliderLow"]:ClearAllPoints()
_G["ColorTools_SatSliderHigh"]:ClearAllPoints()
_G["ColorTools_SatSliderText"]:ClearAllPoints()

-- Copy values.
local red, green, blue, opacity

local copy = CreateFrame("Button", nil, CPF, "OptionsButtonTemplate")
copy:SetText("Copy")
copy:SetPoint("BOTTOMLEFT", CPF, "TOPLEFT", 10, -2)
copy:SetScript("OnClick", function()
	red, green, blue = CPF:GetColorRGB()
	opacity = OSF:GetValue()

	copy:SetText(format("|cff%02x%02x%02xCopy", red * 255, green * 255, blue * 255))
end)

local paste = CreateFrame("Button", nil, CPF, "OptionsButtonTemplate")
paste:SetText("Paste")
paste:SetPoint("BOTTOMRIGHT", CPF, "TOPRIGHT", -10, -2)
paste:SetScript("OnClick", function()
	CPF:SetColorRGB(red, green, blue)
	OSF:SetValue(opacity)
end)

local editboxes = {
	Red = 0,
	Green = 1,
	Blue = 2,
	Alpha = 3
}

local UpdateCPFHSV = function()
	local s = saturation:GetValue()
	local h, _, v = CPF:GetColorHSV()
	CPF:SetColorHSV(h, s, v)
end

local UpdateCPFRGB = function(editbox)
	local r, g, b
	-- hex value
	if #editbox:GetText() == 6 then
		local rgb = editbox:GetText()
		r, g, b = tonumber("0x"..strsub(rgb, 0, 2)), tonumber("0x"..strsub(rgb, 3, 4)), tonumber("0x"..strsub(rgb, 5, 6))
	-- numerical value
	else
		r, g, b = tonumber(editboxes.Red:GetText()), tonumber(editboxes.Green:GetText()), tonumber(editboxes.Blue:GetText())
	end

	-- lazy way to prevent most errors with invalid entries (letters)
	if r and g and b then
		-- % based
		if r <= 1 and g <= 1 and b <= 1 then
			CPF:SetColorRGB(r, g, b)
		-- 0 - 255 based
		else
			CPF:SetColorRGB(r / 255, g / 255, b / 255)
		end
	else
		print("|cffFF0000ColorTools|r: Error converting fields to numbers. Please check the values.")
	end

	-- update opacity
	OSF:SetValue(1 - (tonumber(editboxes.Alpha:GetText()) / 100))
end

local UpdateRGBFields = function()
	local _, s = CPF:GetColorHSV()
	saturation:SetValue(s)

	local r, g, b = CPF:GetColorRGB()
	editboxes.Red:SetText(r * 255)
	editboxes.Green:SetText(g * 255)
	editboxes.Blue:SetText(b * 255)

	hex:SetText(format("%02x%02x%02x", r * 255, g * 255, b * 255))
end

local UpdateAlphaField = function()
	editboxes.Alpha:SetText(100 - (OSF:GetValue() * 100))
end

saturation:SetScript("OnValueChanged", UpdateCPFHSV)
hex:SetScript("OnEnterPressed", function(self)
	UpdateCPFRGB(self)
	self:ClearFocus()
end)

for type, offsetFactor in pairs(editboxes) do
	local editbox = CreateFrame("EditBox", nil, CPF)
	editbox:SetHeight(15)
	editbox:SetWidth(50)
	editbox:SetPoint("TOP", ColorSwatch, "BOTTOM", 0, -5 - (25 * offsetFactor))
	editbox:SetBackdrop({
		bgFile = [[Interface\ChatFrame\ChatFrameBackground]],
	})
	editbox:SetBackdropColor(0, 0, 0, .5)

	editbox:SetFontObject(ChatFontNormal)
	editbox:SetAutoFocus(false)
	editbox:SetMaxLetters(4)
	editbox:SetJustifyH("LEFT")

	editbox:SetScript("OnEscapePressed", function(self)
		self:ClearFocus()
	end)
	editbox:SetScript("OnEnterPressed", function(self)
		UpdateCPFRGB(self)
		self:ClearFocus()
	end)
	editbox:SetScript("OnEditFocusGained", function(self)
		self:HighlightText(0, self:GetNumLetters())
	end)
	editbox:SetScript("OnEditFocusLost", function(self)
		self:HighlightText(self:GetNumLetters())
	end)

	local title = editbox:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
	title:SetText(strmatch(type, "^%S"))
	title:SetPoint("RIGHT", editbox, "LEFT", -3, 0)

	editboxes[type] = editbox
end

editboxes.Red:SetScript("OnTabPressed", function()
	if IsShiftKeyDown() then
		if CPF.hasOpacity then
			editboxes.Alpha:SetFocus()
		else
			editboxes.Blue:SetFocus()
		end
	else
		editboxes.Green:SetFocus()
	end
end)

editboxes.Green:SetScript("OnTabPressed", function()
	if IsShiftKeyDown() then
		editboxes.Red:SetFocus()
	else
		editboxes.Blue:SetFocus()
	end
end)

editboxes.Blue:SetScript("OnTabPressed", function()
	if IsShiftKeyDown() then
		editboxes.Green:SetFocus()
	else
		if CPF.hasOpacity then
			editboxes.Alpha:SetFocus()
		else
			editboxes.Red:SetFocus()
		end
	end
end)

editboxes.Alpha:SetScript("OnTabPressed", function()
	if IsShiftKeyDown() then
		editboxes.Blue:SetFocus()
	else
		editboxes.Red:SetFocus()
	end
end)

CPF:HookScript("OnShow", function()
	CPF:SetWidth(350)

	if CPF.hasOpacity then
		editboxes.Alpha:Show()
	else
		editboxes.Alpha:Hide()
	end

	ColorPickerOkayButton:ClearAllPoints()
	ColorPickerOkayButton:SetPoint("BOTTOMLEFT", CPF, "BOTTOMLEFT", 10, 10)
	ColorPickerCancelButton:ClearAllPoints()
	ColorPickerCancelButton:SetPoint("BOTTOMRIGHT", CPF, "BOTTOMRIGHT", -10, 10)

	UpdateRGBFields()
end)
CPF:HookScript("OnColorSelect", UpdateRGBFields)
OSF:HookScript("OnShow", UpdateAlphaField)
OSF:HookScript("OnValueChanged", UpdateAlphaField)