You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
bastion/libs/StdUi/widgets/ColorPicker.lua

324 lines
9.2 KiB

--- @type StdUi
local StdUi = LibStub and LibStub('StdUi', true);
if not StdUi then
return
end
local module, version = 'ColorPicker', 6;
if not StdUi:UpgradeNeeded(module, version) then
return
end
local ColorPickerMethods = {
SetColorRGBA = function(self, r, g, b, a)
self:SetColorAlpha(a);
self:SetColorRGB(r, g, b);
self.newTexture:SetVertexColor(r, g, b, a);
end,
GetColorRGBA = function(self)
local r, g, b = self:GetColorRGB();
return r, g, b, self:GetColorAlpha();
end,
SetColor = function(self, c)
self:SetColorAlpha(c.a or 1);
self:SetColorRGB(c.r, c.g, c.b);
self.newTexture:SetVertexColor(c.r, c.g, c.b, c.a or 1);
end,
GetColor = function(self)
local r, g, b = self:GetColorRGB();
return { r = r, g = g, b = b, a = self:GetColorAlpha() };
end,
SetColorAlpha = function(self, a, fromSlider)
a = Clamp(a, 0, 1);
if not fromSlider then
self.alphaSlider:SetValue(100 - a * 100);
end
self.aEdit:SetValue(Round(a * 100));
self.aEdit:Validate();
self:SetColorRGB(self:GetColorRGB());
end,
GetColorAlpha = function(self)
local a = Clamp(tonumber(self.aEdit:GetValue()) or 100, 0, 100);
return a / 100;
end
};
local ColorPickerEvents = {
OnColorSelect = function(self)
-- Ensure custom fields are updated.
local r, g, b, a = self:GetColorRGBA();
if not self.skipTextUpdate then
self.rEdit:SetValue(r * 255);
self.gEdit:SetValue(g * 255);
self.bEdit:SetValue(b * 255);
self.aEdit:SetValue(100 * a);
self.rEdit:Validate();
self.gEdit:Validate();
self.bEdit:Validate();
self.aEdit:Validate();
end
self.newTexture:SetVertexColor(r, g, b, a);
self.alphaTexture:SetGradientAlpha('VERTICAL', 1, 1, 1, 0, r, g, b, 1);
end
};
local function OnColorPickerValueChanged(self)
local cpf = self:GetParent();
local r = tonumber(cpf.rEdit:GetValue() or 255) / 255;
local g = tonumber(cpf.gEdit:GetValue() or 255) / 255;
local b = tonumber(cpf.bEdit:GetValue() or 255) / 255;
local a = tonumber(cpf.aEdit:GetValue() or 100) / 100;
cpf.skipTextUpdate = true;
cpf:SetColorRGB(r, g, b);
cpf.alphaSlider:SetValue(100 - a * 100);
cpf.skipTextUpdate = false;
end
--- alphaSliderTexture = [[Interface\AddOns\YourAddon\Libs\StdUi\media\Checkers.tga]]
function StdUi:ColorPicker(parent, alphaSliderTexture)
local wheelWidth = 128;
local thumbWidth = 10;
local barWidth = 16;
local cpf = CreateFrame('ColorSelect', nil, parent);
--self:MakeDraggable(cpf);
cpf:SetPoint('CENTER');
self:ApplyBackdrop(cpf, 'panel');
self:SetObjSize(cpf, 340, 200);
-- Create colorpicker wheel.
cpf.wheelTexture = self:Texture(cpf, wheelWidth, wheelWidth);
self:GlueTop(cpf.wheelTexture, cpf, 10, -10, 'LEFT');
cpf.wheelThumbTexture = self:Texture(cpf, thumbWidth, thumbWidth, [[Interface\Buttons\UI-ColorPicker-Buttons]]);
cpf.wheelThumbTexture:SetTexCoord(0, 0.15625, 0, 0.625);
-- Create the colorpicker slider.
cpf.valueTexture = self:Texture(cpf, barWidth, wheelWidth);
self:GlueRight(cpf.valueTexture, cpf.wheelTexture, 10, 0);
cpf.valueThumbTexture = self:Texture(cpf, barWidth, thumbWidth, [[Interface\Buttons\UI-ColorPicker-Buttons]]);
cpf.valueThumbTexture:SetTexCoord(0.25, 1, 0.875, 0);
cpf:SetColorWheelTexture(cpf.wheelTexture);
cpf:SetColorWheelThumbTexture(cpf.wheelThumbTexture);
cpf:SetColorValueTexture(cpf.valueTexture);
cpf:SetColorValueThumbTexture(cpf.valueThumbTexture);
cpf.alphaSlider = CreateFrame('Slider', nil, cpf);
cpf.alphaSlider:SetOrientation('VERTICAL');
cpf.alphaSlider:SetMinMaxValues(0, 100);
cpf.alphaSlider:SetValue(0);
self:SetObjSize(cpf.alphaSlider, barWidth, wheelWidth + thumbWidth); -- hack
self:GlueRight(cpf.alphaSlider, cpf.valueTexture, 10, 0);
cpf.alphaTexture = self:Texture(cpf.alphaSlider, nil, nil, alphaSliderTexture);
self:GlueAcross(cpf.alphaTexture, cpf.alphaSlider, 0, -thumbWidth / 2, 0, thumbWidth / 2); -- hack
--cpf.alphaTexture:SetColorTexture(1, 1, 1, 1);
--cpf.alphaTexture:SetGradientAlpha('VERTICAL', 0, 0, 0, 1, 1, 1, 1, 1);
cpf.alphaThumbTexture = self:Texture(cpf.alphaSlider, barWidth, thumbWidth,
[[Interface\Buttons\UI-ColorPicker-Buttons]]);
cpf.alphaThumbTexture:SetTexCoord(0.275, 1, 0.875, 0);
cpf.alphaThumbTexture:SetDrawLayer('ARTWORK', 2);
cpf.alphaSlider:SetThumbTexture(cpf.alphaThumbTexture);
cpf.newTexture = self:Texture(cpf, 32, 32, [[Interface\Buttons\WHITE8X8]]);
cpf.oldTexture = self:Texture(cpf, 32, 32, [[Interface\Buttons\WHITE8X8]]);
cpf.newTexture:SetDrawLayer('ARTWORK', 5);
cpf.oldTexture:SetDrawLayer('ARTWORK', 4);
self:GlueTop(cpf.newTexture, cpf, -30, -30, 'RIGHT');
self:GlueBelow(cpf.oldTexture, cpf.newTexture, 20, 45);
----------------------------------------------------
--- Buttons
----------------------------------------------------
cpf.rEdit = self:NumericBox(cpf, 60, 20);
cpf.gEdit = self:NumericBox(cpf, 60, 20);
cpf.bEdit = self:NumericBox(cpf, 60, 20);
cpf.aEdit = self:NumericBox(cpf, 60, 20);
cpf.rEdit:SetMinMaxValue(0, 255);
cpf.gEdit:SetMinMaxValue(0, 255);
cpf.bEdit:SetMinMaxValue(0, 255);
cpf.aEdit:SetMinMaxValue(0, 100);
self:AddLabel(cpf, cpf.rEdit, 'R', 'LEFT');
self:AddLabel(cpf, cpf.gEdit, 'G', 'LEFT');
self:AddLabel(cpf, cpf.bEdit, 'B', 'LEFT');
self:AddLabel(cpf, cpf.aEdit, 'A', 'LEFT');
self:GlueAfter(cpf.rEdit, cpf.alphaSlider, 20, -thumbWidth / 2);
self:GlueBelow(cpf.gEdit, cpf.rEdit, 0, -10);
self:GlueBelow(cpf.bEdit, cpf.gEdit, 0, -10);
self:GlueBelow(cpf.aEdit, cpf.bEdit, 0, -10);
cpf.okButton = StdUi:Button(cpf, 100, 20, OKAY);
cpf.cancelButton = StdUi:Button(cpf, 100, 20, CANCEL);
self:GlueBottom(cpf.okButton, cpf, 40, 20, 'LEFT');
self:GlueBottom(cpf.cancelButton, cpf, -40, 20, 'RIGHT');
----------------------------------------------------
--- Methods
----------------------------------------------------
for k, v in pairs(ColorPickerMethods) do
cpf[k] = v;
end
----------------------------------------------------
--- Events
----------------------------------------------------
cpf.alphaSlider:SetScript('OnValueChanged', function(slider)
cpf:SetColorAlpha((100 - slider:GetValue()) / 100, true);
end);
for k, v in pairs(ColorPickerEvents) do
cpf:SetScript(k, v);
end
cpf.rEdit.OnValueChanged = OnColorPickerValueChanged;
cpf.gEdit.OnValueChanged = OnColorPickerValueChanged;
cpf.bEdit.OnValueChanged = OnColorPickerValueChanged;
cpf.aEdit.OnValueChanged = OnColorPickerValueChanged;
return cpf;
end
local ColorPickerFrameOkCallback = function(self)
local cpf = self:GetParent();
if cpf.okCallback then
cpf.okCallback(cpf);
end
cpf:Hide();
end
local ColorPickerFrameCancelCallback = function(self)
local cpf = self:GetParent();
if cpf.cancelCallback then
cpf.cancelCallback(cpf);
end
cpf:Hide();
end
-- placeholder
function StdUi:ColorPickerFrame(r, g, b, a, okCallback, cancelCallback, alphaSliderTexture)
local colorPickerFrame = self.colorPickerFrame;
if not colorPickerFrame then
colorPickerFrame = self:ColorPicker(UIParent, alphaSliderTexture);
colorPickerFrame:SetFrameStrata('FULLSCREEN_DIALOG');
self.colorPickerFrame = colorPickerFrame;
end
colorPickerFrame.okCallback = okCallback;
colorPickerFrame.cancelCallback = cancelCallback;
colorPickerFrame.okButton:SetScript('OnClick', ColorPickerFrameOkCallback);
colorPickerFrame.cancelButton:SetScript('OnClick', ColorPickerFrameCancelCallback);
colorPickerFrame:SetColorRGBA(r or 1, g or 1, b or 1, a or 1);
colorPickerFrame.oldTexture:SetVertexColor(r or 1, g or 1, b or 1, a or 1);
colorPickerFrame:ClearAllPoints();
colorPickerFrame:SetPoint('CENTER');
colorPickerFrame:Show();
end
local ColorInputMethods = {
SetColor = function(self, c)
if type(c) == 'table' then
self.color.r = c.r;
self.color.g = c.g;
self.color.b = c.b;
self.color.a = c.a or 1;
end
self.target:SetBackdropColor(c.r, c.g, c.b, c.a or 1);
if self.OnValueChanged then
self:OnValueChanged(c);
end
end,
GetColor = function (self, type)
if type == 'hex' then
elseif type == 'rgba' then
return self.color.r, self.color.g, self.color.b, self.color.a
else
-- object
return self.color;
end
end
};
local ColorInputEvents = {
OnClick = function(self)
self.stdUi:ColorPickerFrame(
self.color.r,
self.color.g,
self.color.b,
self.color.a,
function(cpf)
self:SetColor(cpf:GetColor());
end
);
end
};
function StdUi:ColorInput(parent, label, width, height, color)
local button = CreateFrame('Button', nil, parent);
button.stdUi = self;
button:EnableMouse(true);
self:SetObjSize(button, width, height or 20);
self:InitWidget(button);
button.target = self:Panel(button, 16, 16);
button.target.stdUi = self;
button.target:SetPoint('LEFT', 0, 0);
button.text = self:Label(button, label);
button.text:SetPoint('LEFT', button.target, 'RIGHT', 5, 0);
button.text:SetPoint('RIGHT', button, 'RIGHT', -5, 0);
button.color = {r = 1, g = 1, b = 1, a = 1};
if not button.SetBackdrop then
Mixin(button, BackdropTemplateMixin)
end
self:HookDisabledBackdrop(button); --ColorInput has no visual difference when disabled unlike Checkbox
self:HookHoverBorder(button);
for k, v in pairs(ColorInputMethods) do
button[k] = v;
end
for k, v in pairs(ColorInputEvents) do
button:SetScript(k, v);
end
if color then
button:SetColor(color);
end
return button;
end
StdUi:RegisterModule(module, version);