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.

3401 lines
114 KiB

3 years ago
local _, addon = ...
local SettingFunctions = addon.SettingFunctions;
local inOutSine = addon.EasingFunctions.inOutSine;
local FadeFrame = NarciFadeUI.Fade;
local DEFAULT_FRAME_WIDTH = 720; --800 640
local DEFAULT_FRAME_HEIGHT = 405; --450 360
local DEFAULT_LEFT_WIDTH = DEFAULT_FRAME_WIDTH - DEFAULT_FRAME_HEIGHT*4/3;
local SHRIKNED_LEFT_WIDTH = (640 - 360 * 4/3);
local MAX_SCROLLFRAME_WIDTH = 394;
local PADDING_H = 18;
local PADDING_V = 12;
local CATE_LEVEL_OFFSET = 8;
local BUTTON_LEVEL_OFFSET = 12;
local CATE_OFFSET = 64;
local WIDGET_GAP = 16;
local IS_DRAGONFLIGHT = addon.IsDragonflight();
local function IsDragonflightFeature()
return IS_DRAGONFLIGHT
end
local L = Narci.L;
local BIND_ACTION_NARCISSUS = "CLICK Narci_MinimapButton:LeftButton";
_G["BINDING_NAME_"..BIND_ACTION_NARCISSUS] = L["Binding Name Open Narcissus"];
local CategoryButtons;
local CategoryOffsets;
local CategoryTabs;
local OptionButtons;
local WidgetGroups;
local MainFrame;
local AlertMessageFrame;
local Clipboard;
local DB;
local CURRENT_CATE_ID;
local RENDER_RANGE = DEFAULT_FRAME_HEIGHT;
local GAMEPAD_ENABLED = false; --Determine if we need to enable game pad surrpot
local SCROLL_LOCKED = false; --Lock scroll if user is assigning a hotkey
local math = math;
local GetCursorPosition = GetCursorPosition;
local SliderUpdator = CreateFrame("Frame");
local CreditList = {};
local function SetTextColorByID(fontString, id)
if id == 3 then
fontString:SetTextColor(0.92, 0.92, 0.92);
elseif id == 2 then
fontString:SetTextColor(0.67, 0.67, 0.67);
elseif id == 1 then
fontString:SetTextColor(0.40, 0.40, 0.40);
end
end
local function SetTextureColorByID(texture, id)
if id == 3 then
texture:SetVertexColor(0.92, 0.92, 0.92);
elseif id == 2 then
texture:SetVertexColor(0.67, 0.67, 0.67);
elseif id == 1 then
texture:SetVertexColor(0.40, 0.40, 0.40);
end
end
local function Round0(value)
return math.floor(value + 0.5)
end
local function Round1(value)
return math.floor(value * 10 + 0.5) * 0.1
end
local function Round2(value)
return math.floor(value * 100 + 0.5) * 0.01
end
local function OnClick_Checkbox(self)
if self.key then
local state = not DB[self.key];
DB[self.key] = state;
self:UpdateState();
if self.onValueChangedFunc then
self.onValueChangedFunc(self, state);
end
end
end
local function OnClick_Radio(self)
if self.key then
DB[self.key] = self.id;
self:UpdateRadioButtons();
if self.onValueChangedFunc then
self.onValueChangedFunc(self, self.id);
end
end
end
local ULTRAWIDE_MAX_OFFSET;
local ULTRAWIDE_STEP;
local IS_ULTRAWIDE;
local MAX_MODEL_SHRINKAGE = 100;
local function IsUsingUltraWideMonitor()
return IS_ULTRAWIDE
end
do
--Decides if it shows options for extra-wide monitor
local W0, H = WorldFrame:GetSize();
if (W0 and H) and H ~= 0 and (W0 / H) > (16.01 / 9) then --No resizing option on 16:9 or lower
IS_ULTRAWIDE = true;
local SLICE = 4;
local W = H / 9 * 16;
ULTRAWIDE_MAX_OFFSET = ((W0 - W)/2);
ULTRAWIDE_STEP = math.floor(ULTRAWIDE_MAX_OFFSET / SLICE);
ULTRAWIDE_MAX_OFFSET = SLICE * ULTRAWIDE_STEP;
end
local function IsUsingUltraWideMonitor()
return IS_ULTRAWIDE
end
--Calculate max model interactable area skrinkage
MAX_MODEL_SHRINKAGE = Round0( (1/3 - 1/8) *W0 );
end
local SettingsButtonMixin = {};
function SettingsButtonMixin:UpdateState_Checkbox()
self:SetState(self.key and DB[self.key]);
end
function SettingsButtonMixin:UpdateState_Radio()
self:SetState(self.key and DB[self.key] == self.id);
end
NarciSettingsSharedButtonMixin = {};
function NarciSettingsSharedButtonMixin:OnClick()
self:UpdateState();
end
function NarciSettingsSharedButtonMixin:OnEnter()
SetTextColorByID(self.Label, 3);
SetTextureColorByID(self.Border, 3);
if self.onEnterFunc then
self.onEnterFunc(self);
end
end
function NarciSettingsSharedButtonMixin:OnLeave()
SetTextColorByID(self.Label, 2);
SetTextureColorByID(self.Border, 2);
if self.onLeaveFunc then
self.onLeaveFunc(self);
end
end
function NarciSettingsSharedButtonMixin:SetState(state)
if state then
self.Selection:Show();
self.Border:SetTexCoord(0, 0.25, 0, 1);
self.selected = true;
else
self.Selection:Hide();
self.Border:SetTexCoord(0.25, 0.5, 0, 1);
self.selected = nil;
end
if self.children then
for i = 1, #self.children do
self.children[i]:SetShown(state);
end
end
end
function NarciSettingsSharedButtonMixin:SetButtonType(buttonType, keepOnClickScript)
if buttonType == "radio" then
self["UpdateState"] = SettingsButtonMixin["UpdateState_Radio"];
if not keepOnClickScript then
self:SetScript("OnClick", OnClick_Radio);
end
self.Background:SetTexCoord(0.5, 1, 0, 1);
self.Border:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Radio");
self.Selection:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Radio");
self.Highlight:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Radio");
else
self["UpdateState"] = SettingsButtonMixin["UpdateState_Checkbox"];
if not keepOnClickScript then
self:SetScript("OnClick", OnClick_Checkbox);
end
self.Background:SetTexCoord(0, 0.5, 0, 1);
self.Border:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Checkbox");
self.Selection:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Checkbox");
self.Highlight:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Checkbox");
end
self.Background:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\ButtonBackground");
self:OnLeave();
end
function NarciSettingsSharedButtonMixin:SetLabelText(text)
self.Label:SetText(text);
local textWidth = self.Label:GetWrappedWidth();
if textWidth then
if textWidth > 138 then
self:SetWidth(textWidth + 22);
else
self:SetWidth(160);
end
end
end
function NarciSettingsSharedButtonMixin:UpdateRadioButtons()
local groupID = self.groupID;
local buttons = WidgetGroups[groupID];
if buttons then
for i, b in ipairs(buttons) do
b:SetState(b == self);
end
end
end
---- Close Button ----
local function CloseButton_OnEnter(self)
SetTextureColorByID(self.Cross, 3);
end
local function CloseButton_OnLeave(self)
SetTextureColorByID(self.Cross, 1);
end
local function CloseButton_OnMouseDown(self)
self.Cross:SetScale(0.8);
self.Texture:SetTexCoord(0.375, 0.75, 0, 0.75);
end
local function CloseButton_OnMouseUp(self)
self.Cross:SetScale(1);
self.Texture:SetTexCoord(0, 0.375, 0, 0.75);
end
local function CloseButton_OnClick(self)
MainFrame:CloseUI();
end
---- Category Button ----
local function UpdateRenderArea(topOffset)
local bottomOffset = topOffset + RENDER_RANGE;
local tabTop, tabBottom;
for i = 1, NUM_CATE do
tabTop = CategoryOffsets[i] - CATE_OFFSET;
tabBottom = (CategoryOffsets[i + 1] or tabTop) + RENDER_RANGE;
if (tabTop < topOffset and tabBottom > topOffset) or
(tabTop < bottomOffset and tabBottom > bottomOffset) or
(tabTop > topOffset and tabBottom < bottomOffset) then
CategoryTabs[i]:Show();
else
CategoryTabs[i]:Hide();
end
end
end
local function SetCategory(id)
--category button visual
for i, b in ipairs(CategoryButtons) do
if i == id then
b.selected = true;
SetTextColorByID(b.ButtonText, 3);
else
if b.selected then
b.selected = nil;
SetTextColorByID(b.ButtonText, 1);
end
end
end
end
local CREDIT_TAB_ID = 10;
local function FindCurrentCategory(offset)
offset = offset + 135; --is height/3 a proper position?
local matchID;
for i = NUM_CATE, 1, -1 do
if offset >= CategoryOffsets[i] then
matchID = i;
break
end
end
if matchID ~= CURRENT_CATE_ID then
CURRENT_CATE_ID = matchID;
SetCategory(matchID);
CreditList:OnFocused(matchID == CREDIT_TAB_ID);
end
UpdateRenderArea(offset);
end
local function CategoryButton_SetLabel(self, text)
self.ButtonText:SetText(text);
local numLines = self.ButtonText:GetNumLines();
if numLines > 1 then
self:SetHeight(40);
if self.ButtonText:IsTruncated() then
self.ButtonText:SetFontObject("NarciFontMedium12");
end
return 40;
else
return 24;
end
end
local function CategoryButton_OnClick(self)
SetCategory(self.id);
if true then
MainFrame.ScrollFrame:ScrollToOffset(CategoryOffsets[self.id]);
UpdateRenderArea(CategoryOffsets[self.id]);
else
MainFrame.ScrollFrame:SetOffset(CategoryOffsets[self.id]);
end
end
local function CategoryButton_OnEnter(self)
SetTextColorByID(self.ButtonText, 3);
end
local function CategoryButton_OnLeave(self)
if not self.selected then
SetTextColorByID(self.ButtonText, 1);
end
end
---- Feature Preview Pictures ----
local FeaturePreview = {
--textureKey[same as DB key] = {fileName, imageWidth, imageWidth, effectiveWidth, effectiveHeight}
PaperDollWidget = {"Preview-PaperDollWidget", 512, 256, 250, 185},
ConduitTooltip = {"Preview-ConduitTooltip", 512, 256, 256, 188},
NameTranslationPosition1 = {"Preview-TranslationOnTooltip", 256, 256, 149, 193},
NameTranslationPosition2 = {"Preview-TranslationOnNameplate", 256, 256, 149, 193},
};
function FeaturePreview.FadeIn_OnUpdate(f, elapsed)
f.t = f.t + elapsed;
if f.t > -0.1 and f.pendingKey then
FeaturePreview:SetupPreview(f.pendingKey);
f.pendingKey = nil;
FeaturePreview.animIn:Stop();
FeaturePreview.animIn:Play();
end
if f.t >= 0 then
if f.t < 0.25 then
f:SetAlpha(4 * f.t);
else
f:SetAlpha(1);
f:SetScript("OnUpdate", nil);
end
end
end
function FeaturePreview.FadeOut_OnUpdate(f, elapsed)
f.t = f.t + elapsed;
local alpha = f.fromAlpha - 5*f.t;
if alpha > 0 then
f:SetAlpha(alpha);
else
f:SetAlpha(0);
f:SetScript("OnUpdate", nil);
f:Hide();
end
end
function FeaturePreview:SetupPreview(previewKey)
if self[previewKey] and self.anchorTo then
self.texture:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\".. self[previewKey][1]);
local w0, h0 = self[previewKey][2], self[previewKey][3];
local w1, h1 = self[previewKey][4], self[previewKey][5];
self.frame:SetSize(w1 * 0.75, h1 * 0.75);
self.texture:SetTexCoord(1-(w1/w0), 1, 0, h1/h0); --textures are aligned to top-right in the image(tga)
self.frame:ClearAllPoints();
local offsetY = self.anchorTo:GetTop() - MainFrame.ScrollFrame:GetTop();
self.frame:SetPoint("TOPRIGHT", MainFrame.ScrollFrame, "TOPRIGHT", -PADDING_H, offsetY);
if self.frame:GetBottom() < MainFrame.ScrollFrame:GetBottom() + PADDING_H then
self.frame:ClearAllPoints();
self.frame:SetPoint("BOTTOMRIGHT", MainFrame.ScrollFrame, "BOTTOMRIGHT", -PADDING_H, PADDING_H);
end
end
end
function FeaturePreview.ShowPreview(anchorTo)
if not anchorTo.previewKey then return end;
local self = FeaturePreview;
if not self.frame then
self.frame = CreateFrame("Frame", nil, MainFrame.ScrollFrame.ScrollChild);
self.frame:SetSize(16, 16);
self.texture = self.frame:CreateTexture(nil, "OVERLAY");
self.texture:SetPoint("TOPLEFT", self.frame, "TOPLEFT", 0, 0);
self.texture:SetPoint("BOTTOMRIGHT", self.frame, "BOTTOMRIGHT", 0, 0);
self.frame:SetScript("OnHide", function(f)
f:Hide();
f:ClearAllPoints();
f:SetScript("OnUpdate", nil);
end);
self.animIn = self.frame:CreateAnimationGroup();
local ag = self.animIn;
--[[
local path = ag:CreateAnimation("Path");
path:SetDuration(0.5);
path:SetStartDelay(0.08);
local p1 = path:CreateControlPoint(nil, nil, 1);
p1:SetOffset(0, -8);
local p2 = path:CreateControlPoint(nil, nil, 2);
p2:SetOffset(0, 0);
--]]
local tran1 = ag:CreateAnimation("translation");
tran1:SetDuration(0);
tran1:SetOrder(1);
tran1:SetOffset(0, -8);
local tran2 = ag:CreateAnimation("translation");
tran2:SetSmoothing("OUT");
tran2:SetDuration(0.25);
tran2:SetOrder(1);
tran2:SetStartDelay(0.08);
tran2:SetOffset(0, 8);
self.tran1 = tran1;
self.tran2 = tran2;
end
local deltaX, deltaY = GetCursorDelta();
local d = math.sqrt(deltaX*deltaX + deltaY*deltaY);
if d == 0 then
self.tran1:SetOffset(0, 0);
self.tran2:SetOffset(0, 0);
else
self.tran1:SetOffset(-deltaX, -deltaY);
self.tran2:SetOffset(deltaX, deltaY);
end
self.texture:SetTexture(nil);
self.anchorTo = anchorTo;
self.frame.pendingKey = anchorTo.previewKey;
self.frame:SetAlpha(0);
self.frame.t = -0.2;
self.frame:SetScript("OnUpdate", self.FadeIn_OnUpdate);
self.frame:Show();
end
function FeaturePreview.HidePreview()
local self = FeaturePreview;
if self.frame then
self.frame.fromAlpha = self.frame:GetAlpha();
if self.frame.fromAlpha > 0 then
self.frame.t = 0;
self.frame:SetScript("OnUpdate", self.FadeOut_OnUpdate);
self.frame:Show();
else
self.frame:Hide();
end
end
end
---- Options ----
local function AFKToggle_OnValueChanged(self, state)
SettingFunctions.UseAFKScreen(state);
end
local function ItemTooltipStyle_OnValueChanged(self, styleID)
SettingFunctions.SetItemTooltipStyle(styleID)
end
local function ItemTooltipShowItemID_OnValueChanged(self, state)
SettingFunctions.ShowItemIDOnTooltip(state);
end
local function ValueFormat_LetterboxRatio(value)
return Round2(value) ..":1"
end
local function DoubleTap_Setup(self)
local hotkey1, hotkey2 = GetBindingKey("TOGGLECHARACTER0");
local labelText = L["Double Tap"];
if hotkey1 then
labelText = labelText.." |cffffd100("..hotkey1..")|r";
if hotkey2 then
labelText = labelText .. "|cffffffff or |cffffd100("..hotkey2..")|r";
end
else
labelText = labelText.." |cff636363("..(NOT_APPLICABLE or "N/A")..")";
end
self:SetLabelText(labelText);
end
local function DoubleTap_OnValueChanged(self, state)
end
local function UseEscapeKey_OnValueChanged(self, state)
SettingFunctions.UseEscapeKeyForExit(state);
end
local function ItemTooltipStyle_OnEnter(self)
self.slotID = 16;
NarciEquipmentTooltip:HideTooltip();
NarciGameTooltip:Hide();
local link = "|Hitem:71086:6226:173127::::::60:577:::3:6660:7575:7696|r"; --77949
if self.id == 1 then
if Narci_Character:IsShown() then
NarciEquipmentTooltip:SetParent(Narci_Character);
else
NarciEquipmentTooltip:SetParent(UIParent);
end
NarciEquipmentTooltip:SetItemLinkAndAnchor(link, self);
NarciEquipmentTooltip:ShowHotkey(false);
elseif self.id == 2 then
if Narci_Character:IsShown() then
NarciGameTooltip:SetParent(Narci_Character);
else
NarciGameTooltip:SetParent(UIParent);
end
NarciGameTooltip:SetItemLinkAndAnchor(link, self);
end
end
local function ItemTooltipStyle_OnLeave(self)
NarciEquipmentTooltip:HideTooltip();
NarciEquipmentTooltip:SetParent(Narci_Character);
NarciEquipmentTooltip:ShowHotkey(true);
NarciGameTooltip:Hide();
NarciGameTooltip:SetParent(Narci_Character);
end
local function VignetteStrength_OnValueChanged(self, value)
SettingFunctions.SetVignetteStrength(value);
end
local function WeatherEffectToggle_OnValueChanged(self, state)
Narci_SnowEffect(state);
end
local function Letterbox_IsCompatible()
local scale = UIParent:GetEffectiveScale();
local w, h = GetScreenWidth()*scale, GetScreenHeight()*scale;
local ratio = 2;
local croppedHeight = w/ratio; --2.35/2/1.8
local maskHeight = math.floor((h - croppedHeight)/2 - 0.5);
return maskHeight > 0
end
local function LetterboxToggle_OnValueChanged(self, state)
SettingFunctions.UpdateLetterboxSize();
if state then
NarciAPI_LetterboxAnimation("IN");
else
NarciAPI_LetterboxAnimation("OUT");
end
end
local function LetterboxRatio_OnValueChanged(self, value)
SettingFunctions.UpdateLetterboxSize(value);
end
local function UltraWideOffset_OnValueChanged(self, value)
SettingFunctions.SetUltraWideFrameOffset(value);
end
local function ShowMisingEnchantAlert_OnValueChanged(self, state)
SettingFunctions.EnableMissingEnchantAlert(state);
end
local function ShowMisingEnchantAlert_IsValid()
return NarciAPI.IsPlayerAtMaxLevel();
end
local function ShowDetailedStats_OnValueChanged(self, state)
SettingFunctions.ShowDetailedStats(state);
end
local function CharacterUIScale_OnValueChanged(self, scale)
SettingFunctions.SetCharacterUIScale(scale);
end
local function ItemNameHeight_OnValueChanged(self, height)
SettingFunctions.SetItemNameTextHeight(height);
end
local function ItemNameWidth_OnValueChanged(self, width)
SettingFunctions.SetItemNameTextWidth(width);
end
local function TruncateTextToggle_OnValueChanged(self, state)
SettingFunctions.SetItemNameTruncated(state);
end
local function ShowMinimapModulePanel_OnValueChanged(self, state)
SettingFunctions.ShowMinimapModulePanel(state);
end
local function IndependentMinimapButtonToggle_OnValueChanged(self, state)
Narci_MinimapButton:SetIndependent(state);
end
local function ResetMinimapPosition_Setup(self)
self.Border:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\ResetButton");
self.Border:SetTexCoord(0, 1, 0, 1);
self.Selection:Hide();
self.Selection:SetTexture(nil);
self.Highlight:SetTexture(nil);
self.Background:Hide();
self.Background:SetTexture(nil);
local animRotate = self.Border:CreateAnimationGroup();
local r1 = animRotate:CreateAnimation("Rotation");
r1:SetDuration(1);
r1:SetOrder(1);
r1:SetDegrees(360);
r1:SetSmoothing("IN_OUT");
function self:UpdateState()
return
end
self.onEnterFunc = function()
self.Border:SetVertexColor(1, 1, 1);
end
self.onLeaveFunc = function()
SetTextureColorByID(self.Border, 2);
end
self.onLeaveFunc();
self:SetScript("OnClick", function()
Narci_MinimapButton:ResetPosition();
animRotate:Play();
end);
end
local function ScreenshotQuality_GetValue()
local value = C_CVar.GetCVar("screenshotQuality");
return tonumber(value)
end
local function ScreenshotQuality_OnValueChanged(self, value)
C_CVar.SetCVar("screenshotQuality", value);
end
local function ModelPanelScale_OnValueChanged(self, value)
SettingFunctions.SetModelPanelScale(value);
end
local function GetOppositeValue(value)
value = Round0(value);
if value > 0 then
return -value
else
return value
end
end
local function ModelHitRectShrinkage_OnValueChanged(self, value)
SettingFunctions.SetModelHitRectShrinkage(value);
end
local function CameraTransition_SetupDescription(self)
if DB[self.key] then
if self.description then
self.description:SetText(L["Camera Transition Description On"])
end
else
if self.description then
self.description:SetText(L["Camera Transition Description Off"])
end
end
end
local function CameraTransition_OnValueChanged(self, state)
SettingFunctions.UseCameraTransition(state);
CameraTransition_SetupDescription(self);
end
local function CameraOrbitToggle_SetupDescription(self)
if DB[self.key] then
if self.description then
self.description:SetText(L["Orbit Camera Description On"])
end
else
if self.description then
self.description:SetText(L["Orbit Camera Description Off"])
end
end
end
local function CameraOrbitToggle_OnValueChanged(self, state)
if Narci_Character:IsVisible() then
MoveViewRightStop();
if state then
local speed = tonumber(GetCVar("cameraYawMoveSpeed")) or 180;
MoveViewRightStart(0.005*180/speed);
end
end
CameraOrbitToggle_SetupDescription(self);
end
local function CameraSafeToggle_IsValid()
if IsAddOnLoaded("DynamicCam") then
return false
else
return true
end
end
local function CameraSafeToggle_OnValueChanged(self, state)
SettingFunctions.EnableCameraSafeMode(state);
end
local function CameraUseBustShot_OnValueChanged(self, value)
SettingFunctions.SetDefaultZoomClose(value);
end
local function GemManagerToggle_OnValueChanged(self, state)
if (not state) and Narci_EquipmentOption then
Narci_EquipmentOption:CloseUI();
end
end
local function DressingRoomToggle_OnValueChanged(self, state)
if (state and not NarciDressingRoomOverlay) or (not state and NarciDressingRoomOverlay) then
AlertMessageFrame:ShowRequiresReload();
end
end
local function PaperDollWidgetToggle_OnValueChanged(self, state)
SettingFunctions.EnablePaperDollWidget(state);
end
local function ConduitTooltipToggle_OnValueChanged(self, state)
SettingFunctions.EnableConduitTooltip(state);
end
-- dropping hearts when creadit list is focused
local LoveGenerator = {};
function LoveGenerator.HeartAnimationOnStop(animGroup)
local tex = animGroup:GetParent();
tex:Hide();
table.insert(LoveGenerator.recyledTextures, tex);
end
function LoveGenerator:GetHeart()
if not self.textures then
self.textures = {};
end
if not self.recyledTextures then
self.recyledTextures = {};
end
if #self.recyledTextures > 0 then
return table.remove(self.recyledTextures, #self.recyledTextures)
else
local tex = MainFrame.HeartContainer:CreateTexture(nil, "OVERLAY", "NarciPinkHeartTemplate", 2);
tex.FlyDown:SetScript("OnFinished", LoveGenerator.HeartAnimationOnStop);
tex.FlyDown:SetScript("OnStop", LoveGenerator.HeartAnimationOnStop);
self.textures[ #self.textures + 1 ] = tex;
return tex
end
end
function LoveGenerator:CreateHeartAtCursorPosition()
if MainFrame.HeartContainer:IsMouseOver() then
local heart = self:GetHeart();
local px, py = GetCursorPosition();
local scale = MainFrame:GetEffectiveScale();
px, py = px / scale, py / scale;
local d = math.max(py - MainFrame:GetBottom() + 16, 0); --distance
local depth = math.random(1, 8);
local scale = 0.25 + 0.25 * depth;
local size = 32 * scale;
local alpha = 1.35 - 0.15 * depth;
local v = 20 + 10 * depth;
local t= d / v;
if alpha > 0.67 then
alpha = 0.67;
end
heart.FlyDown.Translation:SetOffset(0, -d);
heart.FlyDown.Translation:SetDuration(t);
heart:ClearAllPoints();
heart:SetPoint("CENTER", UIParent, "BOTTOMLEFT" , px, py);
heart:SetSize(size, size);
heart:SetAlpha(alpha);
heart.FlyDown:Play();
heart:Show();
end
end
function LoveGenerator:StopAnimation()
if self.textures then
for _, tex in ipairs(self.textures) do
tex.FlyDown:Stop();
end
end
end
function CreditList:CreateList(parent, anchorTo, fromOffsetY)
local active = {"Albator S.", "Solanya", "Erik Shafer", "Celierra&Darvian", "Pierre-Yves Bertolus", "Terradon", "Alex Boehm", "Miroslav Kovac", "Ryan Zerbin", "Nisutec"};
local inactive = {"Elexys", "Ben Ashley", "Knightlord", "Brian Haberer", "Andrew Phoenix", "Nantangitan", "Blastflight", "Lars Norberg", "Valnoressa", "Nimrodan", "Brux",
"Karl", "Webb", "acein", "Christian Williamson", "Tzutzu", "Anthony Cordeiro", "Nina Recchia", "heiteo", "Psyloken", "Jesse Blick", "Victor Torres"};
local special = {"Marlamin | WoW.tools", "Keyboardturner | Avid Bug Finder(Generator)", "Meorawr | Wondrous Wisdomball", "Hubbotu | Translator - Russian", "Romanv | Translator - Spanish"};
local numTotal = #active;
local mergedList = active;
local totalHeight;
for i = 1, #inactive do
numTotal = numTotal + 1;
mergedList[numTotal] = inactive[i];
end
local upper = string.upper;
table.sort(mergedList, function(a, b)
return upper(a) < upper(b)
end);
local header = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
header:SetPoint("TOP", anchorTo, "TOP", 0, fromOffsetY);
header:SetText(string.upper("Patrons"));
SetTextColorByID(header, 1);
totalHeight = header:GetHeight() + 12;
fromOffsetY = fromOffsetY - totalHeight;
local numRow = math.ceil(numTotal/3);
local sidePadding = PADDING_H + BUTTON_LEVEL_OFFSET;
self.sidePadding = sidePadding;
self.anchorTo = anchorTo;
self.parent = parent;
local colWidth = (MainFrame.ScrollFrame:GetWidth() - sidePadding*2) / 3;
local text;
local fontString;
local height;
local i = 0;
local maxHeight = 0;
local totalTextWidth = 0;
local width = 0;
local fontStrings = {};
for col = 1, 3 do
fontString = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
fontString:SetWidth(colWidth);
fontString:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", 0, fromOffsetY);
fontString:SetJustifyH("LEFT");
fontString:SetJustifyV("TOP");
fontString:SetSpacing(8);
fontStrings[col] = fontString;
SetTextColorByID(fontString, 1);
text = nil;
for row = 1, numRow do
i = i + 1;
if mergedList[i] then
if text then
text = text .. "\n" .. mergedList[i];
else
text = mergedList[i];
end
end
end
fontString:SetText(text);
height = fontString:GetHeight();
width = fontString:GetWrappedWidth();
totalTextWidth = totalTextWidth + width;
if height > maxHeight then
maxHeight = height;
end
end
self.totalTextWidth = totalTextWidth;
self.fontStrings = fontStrings;
self.offsetY = fromOffsetY;
fromOffsetY = fromOffsetY - maxHeight - 48;
local header2 = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
header2:SetPoint("TOP", anchorTo, "TOP", 0, fromOffsetY);
header2:SetText(string.upper("special thanks"));
SetTextColorByID(header2, 1);
text = nil;
for i = 1, #special do
if i == 1 then
text = special[i];
else
text = text .. "\n" .. special[i];
end
end
fromOffsetY = fromOffsetY - header2:GetHeight() - 12;
fontString = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
fontString:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", sidePadding, fromOffsetY);
fontString:SetJustifyH("LEFT");
fontString:SetJustifyV("TOP");
fontString:SetSpacing(8);
fontString:SetText(text);
SetTextColorByID(fontString, 1);
self.specialNames = fontString;
self.specialNamesOffsetY = fromOffsetY;
totalHeight = Round0(header:GetTop() - fontString:GetBottom() + 36);
self:UpdateAlignment();
wipe(active);
wipe(inactive);
active = nil;
inactive = nil;
return totalHeight
end
function CreditList:UpdateAlignment()
if self.fontStrings then
local offsetX = self.sidePadding;
local parentWidth = MainFrame.ScrollFrame:GetWidth();
local gap = (parentWidth - self.sidePadding*2 - self.totalTextWidth) * 0.5;
for col = 1, 3 do
self.fontStrings[col]:ClearAllPoints();
self.fontStrings[col]:SetPoint("TOPLEFT", self.anchorTo, "TOPLEFT", offsetX, self.offsetY);
offsetX = offsetX + self.fontStrings[col]:GetWrappedWidth() + gap;
end
local specialNameWidth = self.specialNames:GetWrappedWidth();
offsetX = (parentWidth - specialNameWidth) * 0.5;
self.specialNames:SetPoint("TOPLEFT", self.anchorTo, "TOPLEFT", offsetX, self.specialNamesOffsetY);
end
end
function CreditList.TimerOnUpdate(f, elapsed)
f.t = f.t + elapsed;
if f.t > 3 then
f.t = 0;
LoveGenerator:CreateHeartAtCursorPosition();
end
end
function CreditList:OnFocused(state)
if state then
if not self.focused then
self.focused = true;
self.parent.t = 0;
self.parent:SetScript("OnUpdate", CreditList.TimerOnUpdate);
FadeFrame(MainFrame.HeartContainer, 0.5, 1);
end
else
if self.focused then
self.focused = nil;
self.parent:SetScript("OnUpdate", nil);
FadeFrame(MainFrame.HeartContainer, 0.5, 0);
end
end
end
function CreditList:StopAnimation()
if self.focused then
LoveGenerator:StopAnimation();
end
end
local AboutTab = {};
function AboutTab:CreateTab(parent, anchorTo, fromOffsetY)
self.anchorTo = anchorTo;
local sidePadding = PADDING_H + BUTTON_LEVEL_OFFSET;
self.sidePadding = sidePadding;
--Version Info
local fontString = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
fontString:SetJustifyH("LEFT");
fontString:SetJustifyV("TOP");
SetTextColorByID(fontString, 1);
fontString:SetSpacing(8);
fontString:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", sidePadding, fromOffsetY);
local version, releaseDate, timeDiff = NarciAPI.GetAddOnVersionInfo();
local text = L["Version Colon"]..version.."\n"..L["Date Colon"]..releaseDate;
if timeDiff then
text = text .." ("..timeDiff..")";
end
text = text .. "\n"..L["Developer Colon"].."Peterodox";
fontString:SetText(text);
local textHeight = Round0(fontString:GetHeight());
fromOffsetY = fromOffsetY - textHeight - 2*WIDGET_GAP;
--Project Websites
local projectHeader = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
projectHeader:SetJustifyH("LEFT");
projectHeader:SetJustifyV("TOP");
SetTextColorByID(projectHeader, 1);
projectHeader:SetText(L["Project Page"]);
projectHeader:SetPoint("TOP", anchorTo, "TOP", 0, fromOffsetY);
self.projectHeader = projectHeader;
--Animation after successfully copying link
local animFadeIn = projectHeader:CreateAnimationGroup();
local fadeIn1 = animFadeIn:CreateAnimation("Alpha");
fadeIn1:SetOrder(1);
fadeIn1:SetFromAlpha(0);
fadeIn1:SetToAlpha(1);
fadeIn1:SetDuration(0.25);
local animSuccess = projectHeader:CreateAnimationGroup();
projectHeader.animSuccess = animSuccess;
local fadeOut1 = animSuccess:CreateAnimation("Alpha");
fadeOut1:SetOrder(1);
fadeOut1:SetFromAlpha(1);
fadeOut1:SetToAlpha(0);
fadeOut1:SetDuration(0.25);
fadeOut1:SetStartDelay(1);
fadeOut1:SetScript("OnFinished", function()
projectHeader:SetText(L["Project Page"]);
animFadeIn:Play();
end);
fromOffsetY = fromOffsetY - 24;
local addonPages = {
{"Curseforge", "https://wow.curseforge.com/projects/narcissus"};
{"Wago", "https://addons.wago.io/addons/narcissus"},
};
local numWebsiteButton = #addonPages;
local textWidth;
self.websiteButtons = {};
self.websiteButtonFromOffsetY = fromOffsetY;
for i = 1, numWebsiteButton do
self.websiteButtons[i] = CreateFrame("Button", nil, parent, "NarciSettingsClipboardButtonTemplate");
self.websiteButtons[i]:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", sidePadding, fromOffsetY);
self.websiteButtons[i].ButtonText:SetText(addonPages[i][1]);
self.websiteButtons[i].link = addonPages[i][2];
self.websiteButtons[i].Logo:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Website-"..addonPages[i][1]);
textWidth = self.websiteButtons[i].ButtonText:GetWrappedWidth();
self.websiteButtons[i].ButtonText:SetWidth(textWidth + 2);
self.websiteButtons[i].id = i;
end
fromOffsetY = fromOffsetY - 48 - 2*WIDGET_GAP;
--Other Notes & Social Media
local notes = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
notes:SetJustifyH("LEFT");
notes:SetJustifyV("TOP");
notes:SetSpacing(4);
notes:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", sidePadding, fromOffsetY);
notes:SetPoint("RIGHT", anchorTo, "RIGHT", -sidePadding, 0);
notes:SetText(L["AboutTab Developer Note"]);
SetTextColorByID(notes, 1);
local platLogo, platName;
for i = 1, 2 do
platLogo = parent:CreateTexture(nil, "OVERLAY");
platLogo:SetSize(24, 24);
platLogo:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\PlatformLogo");
if i == 1 then
platLogo:SetPoint("TOPLEFT", notes, "BOTTOMLEFT", 0, -24 + 4)
platLogo:SetTexCoord(0, 0.5, 0, 1);
else
platLogo:SetPoint("LEFT", platName, "RIGHT", 24, 0);
platLogo:SetTexCoord(0.5, 1, 0, 1);
end
platName = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
platName:SetJustifyH("LEFT");
platName:SetJustifyV("MIDDLE");
platName:SetText("Peterodox");
platName:SetPoint("LEFT", platLogo, "RIGHT", 2, 0);
SetTextColorByID(platName, 1);
SetTextureColorByID(platLogo, 2);
end
end
function AboutTab:UpdateWebsiteButtons(selectedButtonID)
if self.websiteButtons then
local parentWidth = MainFrame.ScrollFrame:GetWidth();
local numWebsiteButton = #self.websiteButtons;
local websiteButtonGap = BUTTON_LEVEL_OFFSET;
if selectedButtonID then
--make the selected one maximized and minimize other ones
self.projectHeader:StopAnimating();
self.projectHeader:SetText(L["Press Copy Yellow"]);
local fromOffsetX = self.sidePadding;
local minimizedWidth = 36.0;
local maximizedWidth = Round0( parentWidth - 2*self.sidePadding - (numWebsiteButton - 1) * (minimizedWidth + websiteButtonGap) )
for i, button in ipairs(self.websiteButtons) do
button:ClearAllPoints();
button:SetPoint("TOPLEFT", self.anchorTo, "TOPLEFT", fromOffsetX, self.websiteButtonFromOffsetY);
if button.id == selectedButtonID then
button:SetLogoOnlyMode(false);
button.ButtonText:Hide();
button:SetWidth(maximizedWidth);
fromOffsetX = fromOffsetX + maximizedWidth + websiteButtonGap;
else
button:SetLogoOnlyMode(true);
button:SetWidth(minimizedWidth);
button.isActive = nil;
if not button:IsMouseOver() then
button:OnLeave();
end
fromOffsetX = fromOffsetX + minimizedWidth + websiteButtonGap;
end
end
else
--equal width
if not self.projectHeader.animSuccess:IsPlaying() then
self.projectHeader:SetText(L["Project Page"]);
end
local websiteButtonWidth = Round0( (parentWidth - 2*self.sidePadding - (numWebsiteButton - 1)*websiteButtonGap) / numWebsiteButton );
for i, button in ipairs(self.websiteButtons) do
button:ClearAllPoints();
button:SetPoint("TOPLEFT", self.anchorTo, "TOPLEFT", self.sidePadding + (i - 1)*(websiteButtonWidth + websiteButtonGap), self.websiteButtonFromOffsetY);
button:SetWidth(websiteButtonWidth);
button.maximizedWidth = websiteButtonWidth;
button:SetLogoOnlyMode(false);
button.Logo:Show();
button.isActive = nil;
if button:IsMouseOver() then
button:OnEnter();
else
button:OnLeave();
end
end
end
end
end
---- Minimap Button Skin ----
local MinimapButtonSkin = {};
function MinimapButtonSkin.OnEnter(self)
self.AnimIn:Stop();
self.AnimDelay:Stop();
self.AnimDelay:Play();
SetTextColorByID(self.SkinName, 3);
end
function MinimapButtonSkin.OnDelayFinished(self)
local button = self:GetParent();
button.AnimIn:Play();
button.AnimIn.Bounce1:SetDuration(0.2);
button.AnimIn.Bounce2:SetDuration(0.2);
button.AnimIn.Hold1:SetDuration(20);
button.AnimIn.Hold2:SetDuration(20);
FadeFrame(button.HighlightTexture, 0.2, 1);
end
function MinimapButtonSkin.OnLeave(self)
self.AnimDelay:Stop();
self.AnimIn.Bounce1:SetDuration(0);
self.AnimIn.Bounce2:SetDuration(0);
self.AnimIn.Hold1:SetDuration(0);
self.AnimIn.Hold2:SetDuration(0);
FadeFrame(self.HighlightTexture, 0.2, 0);
SetTextColorByID(self.SkinName, 2);
end
function MinimapButtonSkin.OnClick(self)
NarcissusDB.MinimapIconStyle = self.skinID;
Narci_MinimapButton:SetBackground();
MinimapButtonSkin:UpdateState();
end
function MinimapButtonSkin.CreateOptions(parentLabel, parent, anchorTo, fromOffsetY)
local data = {
{"Minimap\\LOGO-Cyan", "Dark"},
{"Minimap\\LOGO-Thick", "AzeriteUI"},
{"Minimap\\LOGO-Hollow", "SexyMap"},
{"Minimap\\LOGO-Dragonflight", "Dragonflight"},
};
local buttonWidth = 64;
local buttonHeight = 64;
local buttonPerRow = 4;
local gap = 0;
local self = MinimapButtonSkin;
self.buttonWidth = buttonWidth;
self.buttonHeight = buttonHeight;
self.buttonPerRow = buttonPerRow;
self.gap = gap;
self.fromOffsetY = fromOffsetY + 24;
self.buttons = {};
self.anchorTo = anchorTo;
self.container = CreateFrame("Frame", nil, parent);
--self.container:Hide();
--self.container:SetAlpha(0);
local col, row = 1, 1;
local b;
for i = 1, #data do
self.buttons[i] = CreateFrame("Button", nil, self.container, "NarciMinimapSkinOptionTemplate");
b = self.buttons[i];
if col > buttonPerRow then
col = 1;
row = row + 1;
end
b:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", PADDING_H + (i - 1) * (buttonWidth + gap), fromOffsetY - (row - 1)*(buttonHeight + gap));
b:SetScript("OnEnter", self.OnEnter);
b:SetScript("OnLeave", self.OnLeave);
b:SetScript("OnClick", self.OnClick);
b.AnimDelay:SetScript("OnFinished", self.OnDelayFinished)
b.skinID = i;
b.NormalTexture:SetTexture("Interface\\AddOns\\Narcissus\\Art\\"..data[i][1]);
b.HighlightTexture:SetTexture("Interface\\AddOns\\Narcissus\\Art\\"..data[i][1]);
b.SkinName:SetText(data[i][2]);
SetTextColorByID(b.SkinName, 2);
col = col + 1;
end
MinimapButtonSkin:UpdateAlignment();
table.insert(OptionButtons, MinimapButtonSkin);
local newHeight = row * (buttonHeight + gap) - gap;
local newObj = self.container;
return newHeight, newObj
end
function MinimapButtonSkin:UpdateAlignment()
local parentWidth = MainFrame.ScrollFrame:GetWidth();
--local gap = (parentWidth - 2 * PADDING_H)/self.buttonPerRow;
local gap = (parentWidth - 2 * 30 - (self.buttonWidth*self.buttonPerRow))/(self.buttonPerRow - 1);
if gap > 48 then
gap = 48;
end
local fromOffsetX = 0.5*(parentWidth - (self.buttonPerRow * (self.buttonWidth + gap) - gap) );
local col, row = 1, 0;
for i, b in ipairs(self.buttons) do
if col > self.buttonPerRow then
col = 1;
row = row + 1;
end
b:ClearAllPoints();
b:SetPoint("TOPLEFT", self.anchorTo, "TOPLEFT", fromOffsetX + (i - 1) * (self.buttonWidth + gap), self.fromOffsetY - row*(self.buttonHeight + gap));
end
end
function MinimapButtonSkin:UpdateState()
local skinID = NarcissusDB.MinimapIconStyle;
if not skinID then
skinID = 0;
end
for i, b in ipairs(self.buttons) do
b.Selection:SetShown(i == skinID);
end
end
local function MinimapButtonToggle_OnValueChanged(self, state)
SettingFunctions.ShowMinimapButton(state);
if state then
Narci_MinimapButton:PlayBling();
end
end
local function MinimapButtonFadeOut_OnValueChanged(self, state)
SettingFunctions.FadeOutMinimapButton(state);
end
local LanguageSelector = {};
function LanguageSelector:CreateFrame()
if not self.frame then
self.frame = CreateFrame("Frame", nil, MainFrame.ScrollFrame);
local f = self.frame;
f:Hide();
f:SetSize(400, 300);
local frameLevel = 10;
f:SetPoint("CENTER", MainFrame.ScrollFrame, "CENTER", 0, 0);
f:SetFrameLevel(frameLevel);
f.BorderFrame = CreateFrame("Frame", nil, f);
f.BorderFrame:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
f.BorderFrame:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0);
f.BorderFrame:SetFrameLevel(frameLevel + 6);
f.BackgroundFrame = CreateFrame("Frame", nil, f);
f.BackgroundFrame:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
f.BackgroundFrame:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0);
f.BackgroundFrame:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0);
f.BackgroundFrame:SetFrameLevel(frameLevel - 2);
NarciAPI.NineSliceUtil.SetUp(f.BorderFrame, "settingsBorder", "backdrop");
NarciAPI.NineSliceUtil.SetUp(f.BackgroundFrame, "settingsBackground", "backdrop");
self.header = f:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
self.header:SetJustifyH("CENTER");
self.header:SetPoint("TOP", f, "TOP", 0, -PADDING_V);
SetTextColorByID(self.header, 1);
f:SetScript("OnShow", function()
f:RegisterEvent("GLOBAL_MOUSE_DOWN");
end);
f:SetScript("OnHide", function()
f:UnregisterEvent("GLOBAL_MOUSE_DOWN");
f:Hide();
end);
f:SetScript("OnEvent", function()
if not f:IsMouseOver() then
f:Hide();
end
end);
f:SetScript("OnMouseWheel", function()
f:Hide();
end)
f:SetScript("OnMouseDown", function(_, button)
if button == "RightButton" then
f:Hide();
end
end)
local gameLocale = GetLocale();
local LANGUAGES = {
{"enUS", LFG_LIST_LANGUAGE_ENUS},
{"frFR", LFG_LIST_LANGUAGE_FRFR},
{"deDE", LFG_LIST_LANGUAGE_DEDE},
{"itIT", LFG_LIST_LANGUAGE_ITIT},
{"koKR", LFG_LIST_LANGUAGE_KOKR},
{"ptBR", LFG_LIST_LANGUAGE_PTBR},
{"ruRU", LFG_LIST_LANGUAGE_RURU},
{"esES", ESES},
{"esMX", ESMX},
{"zhCN", ZHCN},
{"zhTW", ZHTW},
};
local MIN_LABEL_WIDTH = 74;
local MAX_ROW = math.ceil(#LANGUAGES / 2);
local row = 0;
local col = 0;
local offsetX = PADDING_H + BUTTON_LEVEL_OFFSET;
local offsetY = -24 - WIDGET_GAP;
self.choiceButtons = {};
local maxLabelThisCol = MIN_LABEL_WIDTH;
local labelWidth, buttonWidth;
local lastColButtonIndex;
local choiceButton;
for i, languageData in ipairs(LANGUAGES) do
row = row + 1;
if row > MAX_ROW then
col = col + 1;
row = 1;
buttonWidth = Round0(maxLabelThisCol + 22);
for j = i-1, i-MAX_ROW, -1 do
self.choiceButtons[j]:SetWidth(buttonWidth);
end
offsetX = offsetX + buttonWidth + 24 + 0.5*WIDGET_GAP;
maxLabelThisCol = MIN_LABEL_WIDTH;
lastColButtonIndex = i;
end
self.choiceButtons[i] = CreateFrame("Button", nil, f, "NarciSettingsSharedButtonTemplate");
choiceButton = self.choiceButtons[i];
choiceButton:SetPoint("TOPLEFT", f, "TOPLEFT", offsetX, offsetY - (row - 1) * (24 + 0.5*WIDGET_GAP));
choiceButton.locale = languageData[1];
choiceButton.Label:SetText(languageData[2]);
choiceButton:SetScript("OnClick", self.ChoiceButton_OnClick);
labelWidth = choiceButton.Label:GetWrappedWidth();
if labelWidth > maxLabelThisCol then
maxLabelThisCol = labelWidth;
end
if languageData[1] == gameLocale then
choiceButton:Disable();
choiceButton.alwaysOn = true;
end
end
buttonWidth = Round0(maxLabelThisCol + 22);
for j = lastColButtonIndex, #self.choiceButtons do
self.choiceButtons[j]:SetWidth(buttonWidth);
end
local frameWidth = math.max( (offsetX + buttonWidth + PADDING_H + BUTTON_LEVEL_OFFSET), Round0(self.header:GetWrappedWidth() + 2*PADDING_H) );
local frameHeight = 36 + WIDGET_GAP + MAX_ROW * (24 + 0.5*WIDGET_GAP);
f:SetSize(frameWidth, frameHeight);
end
end
function LanguageSelector:ShowSelector()
self:CreateFrame();
local isSingleChoice = DB.NameTranslationPosition == 2;
if isSingleChoice ~= self.isSingleChoice then
self.isSingleChoice = isSingleChoice;
local buttonType;
if isSingleChoice then
self.header:SetText(L["Select Language Single"]);
buttonType = "radio";
else
self.header:SetText(L["Select Language Multiple"]);
buttonType = "checkbox";
end
for i, button in ipairs(self.choiceButtons) do
button:SetButtonType(buttonType, true);
if button.alwaysOn then
SetTextColorByID(button.Label, 1);
SetTextureColorByID(button.Selection, 1);
SetTextureColorByID(button.Border, 1);
button.Selection:Hide();
end
end
end
self.frame:Show();
self:UpdateSelection();
end
function LanguageSelector:ToggleSelector()
if self.frame then
self.frame:SetShown(not self.frame:IsShown());
end
end
function LanguageSelector:UpdateSelection()
local languageText;
local isSingleChoice = DB.NameTranslationPosition == 2;
if self.choiceButtons then
if isSingleChoice then
local locale = DB.NamePlateLanguage;
for i, button in ipairs(self.choiceButtons) do
if button.alwaysOn then
button:SetState(false);
else
button:SetState(button.locale == locale);
end
end
languageText = locale;
else
local count = 0;
local isSelected;
for i, button in ipairs(self.choiceButtons) do
if not button.alwaysOn then
isSelected = DB.TooltipLanguages[button.locale];
button:SetState(isSelected);
if isSelected then
count = count + 1;
if count <= 3 then
if languageText then
languageText = languageText..", "..button.locale;
else
languageText = button.locale;
end
end
end
end
end
if count > 3 then
languageText = languageText..", +"..(count - 3);
end
end
else
if isSingleChoice then
local locale = DB.NamePlateLanguage;
if locale then
languageText = locale;
end
else
local count = 0;
for locale, state in pairs(DB.TooltipLanguages) do
if state then
count = count + 1;
if count <= 3 then
if languageText then
languageText = languageText..", "..locale;
else
languageText = locale;
end
end
if count > 3 then
languageText = languageText..", +"..(count - 3);
end
end
end
end
end
if self.toggle then
if languageText then
self.toggle.Label:SetText(languageText);
else
self.toggle.Label:SetText(NONE);
end
end
end
function LanguageSelector.SetupToggle(f)
LanguageSelector.toggle = f;
f:SetScript("OnClick", function ()
LanguageSelector:ShowSelector();
end)
function f:UpdateState()
LanguageSelector:UpdateSelection();
end
f.Border:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\OpenNewWindowButton");
f.Border:SetTexCoord(0, 1, 0, 1);
f.Selection:Hide();
f.Selection:SetTexture(nil);
f.Highlight:SetTexture(nil);
f.Background:Hide();
f.Background:SetTexture(nil);
end
function LanguageSelector:IsCreatureDatabaseLoaded(locale)
locale = locale or "enUS";
if NarciCreatureInfo and NarciCreatureInfo.isLanguageLoaded[locale] then
return true
else
return false
end
end
function LanguageSelector:AreRequiredDatabaseLoaded()
local allLoaded = true;
if DB.TranslateName then
if DB.NameTranslationPosition == 2 then
local locale = DB.NamePlateLanguage;
allLoaded = self:IsCreatureDatabaseLoaded(locale);
else
local locales = DB.TooltipLanguages;
for locale, state in pairs(locales) do
if state then
allLoaded = allLoaded and self:IsCreatureDatabaseLoaded(locale);
if not allLoaded then
break
end
end
end
end
end
if not allLoaded then
return false
end
if DB.SearchRelatives then
allLoaded = self:IsCreatureDatabaseLoaded("enUS");
end
return allLoaded
end
local function UpdateNPCSettings()
if NarciCreatureInfo then
NarciCreatureInfo.UpdateNPCSettings();
end
end
local function CheckReloadRequirement()
local allLoaded = LanguageSelector:AreRequiredDatabaseLoaded();
if allLoaded then
--AlertMessageFrame:Hide();
else
AlertMessageFrame:ShowRequiresReload();
end
end
function LanguageSelector.ChoiceButton_OnClick(f)
if LanguageSelector.isSingleChoice then
DB.NamePlateLanguage = f.locale;
else
DB.TooltipLanguages[f.locale] = not DB.TooltipLanguages[f.locale];
end
LanguageSelector:UpdateSelection();
CheckReloadRequirement();
end
local function TranslateNameToggle_OnValueChanged(self, state)
UpdateNPCSettings();
if state then
CheckReloadRequirement();
end
end
local function NameTranslationPosition_OnValueChanged(self, index)
LanguageSelector:UpdateSelection();
UpdateNPCSettings();
CheckReloadRequirement();
end
local function NameTranslationPosition_Setup(lastRadioButton)
local groupID = lastRadioButton.groupID;
local buttons = WidgetGroups[groupID];
if buttons then
for i, button in ipairs(buttons) do
if i == 2 then
local f = CreateFrame("Frame", nil, button, "NarciSettingsSliderTemplate");
local labelWidth = Round0(button.Label:GetWrappedWidth());
f:SetPoint("TOPLEFT", button, "TOPLEFT", labelWidth, 0);
f.Label:SetText(L["Offset Y"]);
SetTextColorByID(f.Label, 2);
local slider = f.Slider;
SetTextColorByID(slider.ValueText, 2);
slider.key = "NamePlateNameOffset";
slider.valueFormatFunc = Round0;
slider.convertionFunc = Round0;
slider:SetMinMaxValues(-20, 20);
slider:SetObeyStepOnDrag(false);
slider.onValueChangedFunc = function(self, value)
if NarciCreatureInfo then
NarciCreatureInfo.SetNamePlateNameOffset(value);
end
end;
slider.getValueFunc = function()
return tonumber(DB.NamePlateNameOffset) or 0
end;
slider:SetSliderWidth(96, true);
slider:SetValue( slider.getValueFunc() );
f.Label:ClearAllPoints();
f.Label:SetPoint("BOTTOM", slider, "TOP", 0, 2);
f.Label:SetJustifyH("CENTER");
button.children = {};
button.children[1] = f;
end
end
end
end
local function SearchRelativesToggle_OnValueChanged(self, state)
if state then
CheckReloadRequirement();
end
UpdateNPCSettings();
end
local function UpdateAlignment()
MinimapButtonSkin:UpdateAlignment();
CreditList:UpdateAlignment();
AboutTab:UpdateWebsiteButtons();
end
local function AddObjectAsChild(childObject, isTextObject)
local parentObj;
local i;
if isTextObject then
i = #OptionButtons;
else
i = #OptionButtons - 1;
end
parentObj = OptionButtons[i];
while parentObj and parentObj.isChild do
i = i - 1;
parentObj = OptionButtons[i];
end
if parentObj then
if not parentObj.children then
parentObj.children = {};
end
table.insert(parentObj.children, childObject);
childObject.isChild = true;
end
end
local function CreateWidget(parent, anchorTo, offsetX, offsetY, widgetData)
if widgetData.validityCheckFunc then
if not widgetData.validityCheckFunc() then
return nil, 0
end
end
local height;
local widgetType = widgetData.type;
local obj;
local isTextObject;
if widgetType == "header" or widgetType == "subheader" then
height = 12;
isTextObject = true;
else
height = 24;
end
if widgetData.extraTopPadding then
local extraOffset = WIDGET_GAP * widgetData.extraTopPadding;
offsetY = offsetY - extraOffset;
height = height + extraOffset;
end
if widgetData.isNew then
if widgetData.text then
widgetData.text = NARCI_NEW_ENTRY_PREFIX..widgetData.text.."|r"
end
end
if isTextObject then
obj = parent:CreateFontString(nil, "OVERLAY", "NarciFontMedium13");
if widgetData.alignToCenter then
obj:SetPoint("TOP", anchorTo, "TOP", 0, offsetY);
obj:SetJustifyH("CENTER");
else
obj:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", offsetX + ((widgetData.level and widgetData.level * BUTTON_LEVEL_OFFSET) or 0), offsetY);
obj:SetJustifyH("LEFT");
end
obj:SetJustifyV("TOP");
SetTextColorByID(obj, 1);
height = height + WIDGET_GAP;
if widgetType == "header" then
obj:SetText(string.upper(widgetData.text));
else
obj:SetText(widgetData.text);
end
elseif widgetType == "radio" then
local numButtons = #widgetData.texts;
local preview;
local sectorHeight;
if widgetData.previewImage then
preview = parent:CreateTexture(nil, "ARTWORK");
preview:SetSize(widgetData.previewWidth, widgetData.previewHeight);
preview:SetPoint("TOPRIGHT", anchorTo, "TOPRIGHT", -24, offsetY + (widgetData.previewOffsetY or 0));
preview:SetTexture("Interface\\AddOns\\Pitcher\\Art\\Settings\\"..widgetData.previewImage);
sectorHeight = widgetData.previewHeight - (widgetData.previewOffsetY or 0);
AddObjectAsChild(preview);
end
local groupID = #WidgetGroups + 1;
WidgetGroups[groupID] = {};
for i = 1, numButtons do
obj = CreateFrame("Button", nil, parent, "NarciSettingsSharedButtonTemplate");
table.insert(OptionButtons, obj);
obj:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", offsetX + ((widgetData.level and widgetData.level * BUTTON_LEVEL_OFFSET) or 0), offsetY + (1 - i) * (24 + 0.5*WIDGET_GAP));
obj:SetButtonType("radio");
obj.groupID = groupID;
obj.id = i;
obj.key = widgetData.key;
obj:SetLabelText(widgetData.texts[i]);
obj.preview = preview;
SetTextColorByID(obj.Label, 2);
WidgetGroups[groupID][i] = obj;
obj.onValueChangedFunc = widgetData.onValueChangedFunc;
if widgetData.isChild then
AddObjectAsChild(obj);
end
obj.onEnterFunc = widgetData.onEnterFunc;
obj.onLeaveFunc = widgetData.onLeaveFunc;
if widgetData.showFeaturePreview then
obj.previewKey = widgetData.key..i;
end
end
height = (24 + 0.5*WIDGET_GAP) * numButtons;
if sectorHeight and height < sectorHeight then
height = sectorHeight;
end
height = height + WIDGET_GAP;
elseif widgetType == "checkbox" then
obj = CreateFrame("Button", nil, parent, "NarciSettingsSharedButtonTemplate");
table.insert(OptionButtons, obj);
obj:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", offsetX + ((widgetData.level and widgetData.level * BUTTON_LEVEL_OFFSET) or 0), offsetY);
obj:SetButtonType("checkbox");
obj.key = widgetData.key;
obj:SetLabelText(widgetData.text);
SetTextColorByID(obj.Label, 2);
obj.onValueChangedFunc = widgetData.onValueChangedFunc;
if widgetData.description then
local desc = obj:CreateFontString(nil, "OVERLAY", "NarciFontThin13");
obj.description = desc;
SetTextColorByID(desc, 1);
desc:SetSpacing(4);
desc:SetJustifyH("LEFT");
desc:SetJustifyV("TOP");
desc:SetPoint("TOPLEFT", obj.Label, "BOTTOMLEFT", 0, -6);
desc:SetWidth(300);
desc:SetText(widgetData.description);
local extraHeight = obj:GetBottom() - desc:GetBottom();
extraHeight = Round0(extraHeight);
height = height + extraHeight;
end
height = height + WIDGET_GAP;
if widgetData.showFeaturePreview then
obj.previewKey = widgetData.key;
end
elseif widgetType == "slider" then
obj = CreateFrame("Frame", nil, parent, "NarciSettingsSliderTemplate");
local slider = obj.Slider;
table.insert(OptionButtons, slider);
obj:SetPoint("TOPLEFT", anchorTo, "TOPLEFT", offsetX + ((widgetData.level and widgetData.level * BUTTON_LEVEL_OFFSET) or 0), offsetY);
SetTextColorByID(obj.Label, 2);
SetTextColorByID(slider.ValueText, 2);
obj.Label:SetText(widgetData.text);
slider.key = widgetData.key;
slider.valueFormatFunc = widgetData.valueFormatFunc;
slider.convertionFunc = widgetData.convertionFunc;
slider:SetMinMaxValues(widgetData.minValue, widgetData.maxValue);
if widgetData.valueStep then
slider:SetValueStep(widgetData.valueStep);
slider:SetObeyStepOnDrag(true);
else
slider:SetObeyStepOnDrag(false);
end
slider.onValueChangedFunc = widgetData.onValueChangedFunc;
slider.getValueFunc = widgetData.getValueFunc;
if widgetData.sliderWidth then
slider:SetSliderWidth(widgetData.sliderWidth, true);
end
height = height + WIDGET_GAP;
--local left = MainFrame.ScrollFrame:GetLeft();
--local right = slider:GetRight() + PADDING_H;
--print(left - right);
elseif widgetType == "keybinding" then
obj = CreateFrame("Button", nil, parent, "NarciSettingsKeybindingButtonTemplate");
table.insert(OptionButtons, obj);
obj:SetPoint("TOP", anchorTo, "TOP", (widgetData.level and widgetData.level * BUTTON_LEVEL_OFFSET) or 0, offsetY);
obj.Label:SetText(widgetData.text);
if widgetData.externalAction then
obj:SetExternalAction(widgetData.externalAction);
else
obj:SetInternalAction(widgetData.internalAction);
end
height = 24 + WIDGET_GAP;
end
if widgetType ~= "radio" then
obj.onEnterFunc = widgetData.onEnterFunc;
obj.onLeaveFunc = widgetData.onLeaveFunc;
if widgetData.isChild then
AddObjectAsChild(obj, isTextObject);
end
end
if widgetData.setupFunc then
local extraHeight, newObject = widgetData.setupFunc(obj, parent, anchorTo, offsetY - height);
if extraHeight then
height = height + extraHeight;
end
if newObject and widgetData.isChild then
AddObjectAsChild(newObject);
end
end
return obj, Round0(height)
end
local Categories = {
--{ CategoryName }
{name = L["Character Panel"], level = 0,
widgets = {
{type = "header", level = 0, text = L["Character Panel"]},
{type = "slider", level = 1, key = "GlobalScale", text = UI_SCALE, onValueChangedFunc = CharacterUIScale_OnValueChanged, minValue = 0.7, maxValue = 1, valueStep = 0.1, },
{type = "slider", level = 1, key = "BaseLineOffset", text = L["Baseline Offset"], validityCheckFunc = IsUsingUltraWideMonitor, onValueChangedFunc = UltraWideOffset_OnValueChanged, minValue = 0, maxValue = ULTRAWIDE_MAX_OFFSET, valueStep = ULTRAWIDE_STEP, },
{type = "checkbox", level = 1, key = "MissingEnchantAlert", text = L["Missing Enchant Alert"], onValueChangedFunc = ShowMisingEnchantAlert_OnValueChanged, validityCheckFunc = ShowMisingEnchantAlert_IsValid, isNew = true},
{type = "checkbox", level = 1, key = "DetailedIlvlInfo", text = L["Show Detailed Stats"], onValueChangedFunc = ShowDetailedStats_OnValueChanged},
{type = "checkbox", level = 1, key = "AFKScreen", text = L["AFK Screen Description"], onValueChangedFunc = AFKToggle_OnValueChanged, },
{type = "checkbox", level = 3, key = "AKFScreenDelay", text = L["AFK Screen Delay"], onValueChangedFunc = nil, isChild = true},
{type = "subheader", level = 1, text = L["Item Names"], extraTopPadding = 1},
{type = "slider", level = 1, key = "FontHeightItemName", text = FONT_SIZE, onValueChangedFunc = ItemNameHeight_OnValueChanged, minValue = 10, maxValue = 12, valueStep = 1, },
{type = "slider", level = 1, key = "ItemNameWidth", text = L["Text Width"], onValueChangedFunc = ItemNameWidth_OnValueChanged, minValue = 100, maxValue = 200, valueStep = 20, },
{type = "checkbox", level = 1, key = "TruncateText", text = L["Truncate Text"], onValueChangedFunc = TruncateTextToggle_OnValueChanged},
},
},
{name = L["Hotkey"], level = 1,
widgets = {
{type = "header", level = 0, text = L["Hotkey"]},
{type = "keybinding", level = 1, text = L["Open Narcissus"], externalAction = BIND_ACTION_NARCISSUS},
{type = "checkbox", level = 1, key = "EnableDoubleTap", extraTopPadding = 1, text = L["Double Tap"], description = L["Double Tap Description"], onValueChangedFunc = DoubleTap_OnValueChanged, setupFunc = DoubleTap_Setup},
{type = "checkbox", level = 1, key = "UseEscapeButton", text = L["Use Escape Button"], description = L["Use Escape Button Description"], onValueChangedFunc = UseEscapeKey_OnValueChanged},
},
},
{name = L["Item Tooltip"], level = 1,
widgets = {
{type = "header", level = 0, text = L["Item Tooltip"]},
{type = "subheader", level = 1, text= L["Style"]},
{type = "radio", level = 1, key = "ItemTooltipStyle", texts = {L["Tooltip Style 1"], L["Tooltip Style 2"]}, onValueChangedFunc = ItemTooltipStyle_OnValueChanged, onEnterFunc = ItemTooltipStyle_OnEnter, onLeaveFunc = ItemTooltipStyle_OnLeave},
{type = "subheader", level = 1, text = L["Addtional Info"], extraTopPadding = 0},
{type = "checkbox", level = 1, key = "ShowItemID", text = L["Item ID"], onValueChangedFunc = ItemTooltipShowItemID_OnValueChanged},
},
},
{name = L["Screen Effects"], level = 1,
widgets = {
{type = "header", level = 0, text = L["Screen Effects"]},
{type = "slider", level = 1, key = "VignetteStrength", text = L["Vignette Strength"], valueFormatFunc = Round1, convertionFunc = Round1, onValueChangedFunc = VignetteStrength_OnValueChanged, minValue = 0, maxValue = 1, valueStep = nil, },
{type = "checkbox", level = 1, key = "WeatherEffect", text = L["Weather Effect"], onValueChangedFunc = WeatherEffectToggle_OnValueChanged},
{type = "checkbox", level = 1, key = "LetterboxEffect", text = L["Letterbox"], validityCheckFunc = Letterbox_IsCompatible, onValueChangedFunc = LetterboxToggle_OnValueChanged},
{type = "slider", level = 3, key = "LetterboxRatio", text = L["Letterbox Ratio"], validityCheckFunc = Letterbox_IsCompatible, isChild = true, onValueChangedFunc = LetterboxRatio_OnValueChanged, minValue = 2, maxValue = 2.35, valueStep = 0.35, sliderWidth = 64, valueFormatFunc = ValueFormat_LetterboxRatio, },
},
},
{name = L["Camera"], level = 1,
widgets = {
{type = "header", level = 0, text = L["Camera"]},
{type = "checkbox", level = 1, key = "CameraTransition", text = L["Camera Transition"], onValueChangedFunc = CameraTransition_OnValueChanged, description = L["Camera Transition Description Off"], setupFunc = CameraTransition_SetupDescription},
{type = "checkbox", level = 1, key = "CameraOrbit", text = L["Orbit Camera"], onValueChangedFunc = CameraOrbitToggle_OnValueChanged, description = L["Orbit Camera Description On"], setupFunc = CameraOrbitToggle_SetupDescription},
{type = "checkbox", level = 1, key = "CameraSafeMode", text = L["Camera Safe Mode"], onValueChangedFunc = CameraSafeToggle_OnValueChanged, description = L["Camera Safe Mode Description"], validityCheckFunc = CameraSafeToggle_IsValid},
{type = "checkbox", level = 1, key = "UseBustShot", text = L["Use Bust Shot"], onValueChangedFunc = CameraUseBustShot_OnValueChanged},
},
},
{name = L["Minimap Button"], level = 0, --#6
widgets = {
{type = "header", level = 0, text = L["Minimap Button"]},
{type = "checkbox", level = 1, key = "ShowMinimapButton", text = ENABLE, onValueChangedFunc = MinimapButtonToggle_OnValueChanged},
{type = "checkbox", level = 3, customButtonScript = true, text = RESET_POSITION or "Reset Position", isChild = true, setupFunc = ResetMinimapPosition_Setup},
{type = "checkbox", level = 3, key = "ShowModulePanelOnMouseOver", text = L["Show Module Panel Gesture"], isChild = true, onValueChangedFunc = ShowMinimapModulePanel_OnValueChanged},
{type = "checkbox", level = 3, key = "IndependentMinimapButton", text = L["Independent Minimap Button"], isChild = true, onValueChangedFunc = IndependentMinimapButtonToggle_OnValueChanged},
{type = "checkbox", level = 3, key = "FadeButton", text = L["Fade Out Description"], isChild = true, onValueChangedFunc = MinimapButtonFadeOut_OnValueChanged},
{type = "subheader", level = 3, text = L["Style"], extraTopPadding = 1, isChild = true, setupFunc = MinimapButtonSkin.CreateOptions},
},
},
{name = L["Photo Mode"], level = 0,
widgets = {
{type = "header", level = 0, text = L["Photo Mode"]},
{type = "slider", level = 1, key = "screenshotQuality", text = L["Sceenshot Quality"], onValueChangedFunc = ScreenshotQuality_OnValueChanged, minValue = 3, maxValue = 10, getValueFunc = ScreenshotQuality_GetValue, valueFormatFunc = Round0, convertionFunc = Round0},
{type = "subheader", level = 1, text = L["Screenshot Quality Description"]},
{type = "slider", level = 1, key = "ModelPanelScale", text = L["Panel Scale"], onValueChangedFunc = ModelPanelScale_OnValueChanged, minValue = 0.8, maxValue = 1, valueStep = 0.1, extraTopPadding = 1, valueFormatFunc = Round1},
{type = "slider", level = 1, key = "ShrinkArea", text = L["Interactive Area"], onValueChangedFunc = ModelHitRectShrinkage_OnValueChanged, minValue = 0, maxValue = MAX_MODEL_SHRINKAGE, valueFormatFunc = GetOppositeValue, convertionFunc = Round0},
},
},
{name = "NPC", level = 0,
widgets = {
{type = "header", level = 0, text = L["Creature Tooltip"]},
{type = "checkbox", level = 1, key = "SearchRelatives", text = L["Find Relatives"], onValueChangedFunc = SearchRelativesToggle_OnValueChanged, },
{type = "checkbox", level = 1, key = "TranslateName", text = L["Translate Names"], onValueChangedFunc = TranslateNameToggle_OnValueChanged, },
{type = "subheader", level = 3, text = L["Translate Names Description"], extraTopPadding = 0, isChild = true},
{type = "radio", level = 3, key = "NameTranslationPosition", texts = {L["Tooltip"], L["Name Plate"]}, isChild = true, onValueChangedFunc = NameTranslationPosition_OnValueChanged, showFeaturePreview = true, onEnterFunc = FeaturePreview.ShowPreview, onLeaveFunc = FeaturePreview.HidePreview, setupFunc = NameTranslationPosition_Setup},
{type = "subheader", level = 3, text = L["Translate Names Languages"], extraTopPadding = 0, isChild = true},
{type = "checkbox", level = 3, text = "Select Languages", isChild = true, setupFunc = LanguageSelector.SetupToggle},
},
},
{name = L["Extensions"], level = 0,
widgets = {
{type = "header", level = 0, text = "Extensions"},
{type = "checkbox", level = 1, key = "GemManager", text = L["Gem Manager"], onValueChangedFunc = GemManagerToggle_OnValueChanged, description = L["Gemma Description"]},
{type = "checkbox", level = 1, key = "DressingRoom", text = L["Dressing Room"], onValueChangedFunc = DressingRoomToggle_OnValueChanged, description = L["Dressing Room Description"]},
{type = "subheader", level = 1, text = "Expansion Features", extraTopPadding = 1},
{type = "checkbox", level = 1, key = "PaperDollWidget", text = L["Paperdoll Widget"], onValueChangedFunc = PaperDollWidgetToggle_OnValueChanged, showFeaturePreview = true, onEnterFunc = FeaturePreview.ShowPreview, onLeaveFunc = FeaturePreview.HidePreview},
{type = "checkbox", level = 1, key = "ConduitTooltip", text = L["Conduit Tooltip"], onValueChangedFunc = ConduitTooltipToggle_OnValueChanged, showFeaturePreview = true, onEnterFunc = FeaturePreview.ShowPreview, onLeaveFunc = FeaturePreview.HidePreview},
},
},
{name = L["Credits"], level = 0, },
{name = L["About"], level = 0,
widgets = {
{type = "header", level = 0, text = L["About"]},
},
},
};
if IS_DRAGONFLIGHT then
local function ShowTreeCase1(self, state)
SettingFunctions.ShowMiniTalentTreeForPaperDoll(state);
end
local function ShowTreeCase2(self, state)
SettingFunctions.ShowMiniTalentTreeForInspection(state);
end
local function TruncateTalentDescription(self, state)
SettingFunctions.TruncateTalentTreeTooltip(state);
end
local talentCategory = {name = TALENTS or "Talents", level = 1,
widgets = {
{type = "header", level = 0, text = L["Mini Talent Tree"]},
{type = "subheader", level = 1, text = L["Show Talent Tree When"]},
{type = "checkbox", level = 1, key = "TalentTreeForPaperDoll",text = L["Show Talent Tree Paperdoll"], onValueChangedFunc = ShowTreeCase1},
{type = "checkbox", level = 1, key = "TalentTreeForInspection", text = L["Show Talent Tree Inspection"], onValueChangedFunc = ShowTreeCase2},
{type = "subheader", level = 1, text = L["Tooltip"], extraTopPadding = 1},
{type = "checkbox", level = 1, key = "TalentTreeShortTooltip", text = L["Truncate Talent Description"], onValueChangedFunc = TruncateTalentDescription},
}};
table.insert(Categories, #Categories -1, talentCategory);
end
CREDIT_TAB_ID = #Categories - 1;
local function SetupFrame()
if CategoryButtons then return end;
DB = NarcissusDB;
local f = MainFrame;
local texPath = "Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\";
f.CategoryFrame:SetWidth(DEFAULT_LEFT_WIDTH);
f.ScrollFrame.ScrollChild:SetWidth(DEFAULT_FRAME_WIDTH - DEFAULT_LEFT_WIDTH);
f.Divider = f.OverlayFrame:CreateTexture(nil, "OVERLAY", nil, 1);
f.Divider:SetPoint("TOP", f.CategoryFrame, "TOPRIGHT", 0, -1);
f.Divider:SetPoint("BOTTOM", f.CategoryFrame, "BOTTOMRIGHT", 0, 1);
f.Divider:SetWidth(32);
f.Divider:SetTexture(texPath.."DividerVertical");
NarciAPI.NineSliceUtil.SetUp(f.BorderFrame, "settingsBorder", "backdrop");
NarciAPI.NineSliceUtil.SetUp(f.BackgroundFrame, "settingsBackground", "backdrop");
NarciAPI.AddPixelPerfectTexture(f.BorderFrame, f.Divider, 32);
local cateButtonHeight = 24;
local numCate = #Categories;
local bottomCateIndex = numCate - 2;
local frameHeight = Round0(f.ScrollFrame:GetHeight());
CategoryButtons = {};
CategoryOffsets = {};
CategoryTabs = {};
OptionButtons = {};
WidgetGroups = {};
local obj;
local height;
local totalScrollHeight = PADDING_H;
local tab;
local cateHeight, totalCateHeight = 0, 0;
for i, cateData in ipairs(Categories) do
obj = CreateFrame("Button", nil, f.CategoryFrame, "NarciSettingsCategoryButtonTemplate");
CategoryButtons[i] = obj;
CategoryOffsets[i] = totalScrollHeight - PADDING_H;
obj.id = i;
obj.level = cateData.level;
obj:SetScript("OnClick", CategoryButton_OnClick);
obj:SetScript("OnEnter", CategoryButton_OnEnter);
obj:SetScript("OnLeave", CategoryButton_OnLeave);
obj:SetWidth(DEFAULT_LEFT_WIDTH);
obj:SetHitRectInsets(0, 8, 0, 0);
obj.ButtonText:SetPoint("LEFT", obj, "LEFT", PADDING_H + CATE_LEVEL_OFFSET*cateData.level, 0);
SetTextColorByID(obj.ButtonText, 1);
CategoryTabs[i] = CreateFrame("Frame", nil, f.ScrollFrame.ScrollChild);
if i > bottomCateIndex then
obj:SetPoint("BOTTOMLEFT", f.CategoryFrame, "BOTTOMLEFT", 0, PADDING_V + (numCate - i) * cateButtonHeight);
if i == numCate then
--About Tab
else
--Credit List
totalScrollHeight = math.ceil(totalScrollHeight/frameHeight) * frameHeight;
totalScrollHeight = totalScrollHeight + WIDGET_GAP;
CategoryOffsets[i] = totalScrollHeight - PADDING_H;
height = CreditList:CreateList(CategoryTabs[i], f.ScrollFrame.ScrollChild, -totalScrollHeight);
totalScrollHeight = totalScrollHeight + height;
end
else
obj:SetPoint("TOPLEFT", f.CategoryFrame, "TOPLEFT", 0, -PADDING_V -totalCateHeight);
end
cateHeight = CategoryButton_SetLabel(obj, cateData.name);
totalCateHeight = totalCateHeight + cateHeight;
if cateData.widgets then
for j = 1, #cateData.widgets do
obj, height = CreateWidget(CategoryTabs[i], f.ScrollFrame.ScrollChild, PADDING_H, -totalScrollHeight, cateData.widgets[j]);
totalScrollHeight = totalScrollHeight + height;
if obj then
obj.categoryID = i;
end
end
end
if i == numCate then
--About List
AboutTab:CreateTab(CategoryTabs[i], f.ScrollFrame.ScrollChild, -totalScrollHeight);
end
totalScrollHeight = totalScrollHeight + CATE_OFFSET;
end
--Close Button;
local CloseButton = CreateFrame("Button", nil, f.OverlayFrame);
f.CloseButton = CloseButton;
CloseButton:SetSize(36, 36);
CloseButton:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0);
CloseButton.Texture = CloseButton:CreateTexture(nil, "BACKGROUND");
CloseButton.Texture:SetSize(36, 36);
CloseButton.Texture:SetPoint("CENTER", CloseButton, "CENTER", 0, 0);
CloseButton.Texture:SetTexture(texPath.."CloseButton");
CloseButton.Texture:SetTexCoord(0, 0.375, 0, 0.75);
CloseButton.Cross = CloseButton:CreateTexture(nil, "OVERLAY");
CloseButton.Cross:SetSize(18, 18);
CloseButton.Cross:SetPoint("CENTER", CloseButton, "CENTER", 0, 0);
CloseButton.Cross:SetTexture(texPath.."CloseButton");
CloseButton.Cross:SetTexCoord(0.8125, 1, 0, 0.375);
CloseButton:SetScript("OnEnter", CloseButton_OnEnter);
CloseButton:SetScript("OnLeave", CloseButton_OnLeave);
CloseButton:SetScript("OnMouseDown", CloseButton_OnMouseDown);
CloseButton:SetScript("OnMouseUp", CloseButton_OnMouseUp);
CloseButton:SetScript("OnClick", CloseButton_OnClick);
CloseButton_OnLeave(CloseButton);
for _, button in pairs(OptionButtons) do
button:UpdateState();
end
local enableSwipe = true;
local useReachLimitAnimation = true;
NarciAPI.CreateSmoothScroll(f.ScrollFrame, enableSwipe, useReachLimitAnimation);
NUM_CATE = #CategoryOffsets;
local scrollRange = CategoryOffsets[ NUM_CATE ];
f.ScrollFrame:SetScrollRange(scrollRange);
f.ScrollFrame:SetStepSize(80);
f.ScrollFrame:SetSpeedMultiplier(0.2);
f.ScrollFrame:SetOnValueChangedFunc(FindCurrentCategory);
if not AlertMessageFrame then
AlertMessageFrame = CreateFrame("Frame", nil, f, "NarciSettingsAlertFrameTemplate");
end
AlertMessageFrame:Hide();
CategoryButtons[1]:Click();
--Pixel perfect?
local _, screenHeight = GetPhysicalScreenSize();
local scale = 768/screenHeight;
MainFrame:SetScale(scale / 0.75);
MainFrame:RegisterEvent("UI_SCALE_CHANGED");
wipe(Categories);
Categories = nil;
end
NarciSettingsFrameMixin = {};
function NarciSettingsFrameMixin:OnLoad()
MainFrame = self;
local panel = NarciInterfaceOptionsPanel;
panel:HookScript("OnShow", function(f)
if f:IsVisible() then
MainFrame:ShowUI("blizzard");
end
end);
panel:HookScript("OnHide", function(f)
MainFrame:CloseUI();
end);
if IS_DRAGONFLIGHT and SettingsPanel then
self.Background = CreateFrame("Frame", nil, SettingsPanel);
self.Background:SetFrameStrata("LOW");
self.Background:SetFixedFrameStrata(true);
self.Background:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0);
self.Background:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0);
local realTexture = self.Background:CreateTexture(nil, "BACKGROUND")
realTexture:SetPoint("TOPLEFT", self, "TOPLEFT", -58, 14); --30
realTexture:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 32, -4); --8
realTexture:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\DispersiveBackground");
--realTexture:SetColorTexture(1, 0.05, 0.05, 0.8);
--local category = securecallfunction(Settings.RegisterCanvasLayoutCategory, panel, "Narcissus");
--securecallfunction(Settings.RegisterAddOnCategory, category);
local category = Settings.RegisterCanvasLayoutCategory(panel, "Narcissus");
Settings.RegisterAddOnCategory(category);
else
self.Background = self:CreateTexture(nil, "BACKGROUND", nil, -1);
self.Background:SetPoint("TOPLEFT", self, "TOPLEFT", 0, 0);
self.Background:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 0, 0);
self.Background:SetColorTexture(0.05, 0.05, 0.05, 0.8);
--Create UI on Interface Options Panel (ESC-Interface)
panel.name = "Narcissus";
panel.Header:SetText("Narcissus");
InterfaceOptions_AddCategory(panel);
end
self.Background:Hide();
end
function NarciSettingsFrameMixin:ShowUI(mode)
SetupFrame();
mode = mode or "default";
if mode ~= self.mode then
self.mode = mode;
if mode == "blizzard" then
self:AnchorToInterfaceOptions();
else
self:AnchorToDefault();
end
end
CreditList:StopAnimation();
if mode == "default" then
self.FlyIn:Play();
self:SetFrameStrata("HIGH");
self.Background:Hide();
else
self.FlyIn:Stop();
self.Background:Show();
end
RENDER_RANGE = Round0(self.ScrollFrame:GetHeight() + 4 + CATE_OFFSET);
self:Show();
end
function NarciSettingsFrameMixin:CloseUI()
self:Hide();
end
function NarciSettingsFrameMixin:ToggleUI()
if self:IsShown() then
self:CloseUI();
else
self:ShowUI();
end
end
function NarciSettingsFrameMixin:OnHide()
self.FlyIn:Stop();
SliderUpdator:Stop();
SCROLL_LOCKED = false;
self:Hide();
self.Background:Hide();
end
function NarciSettingsFrameMixin:OnEvent(event, ...)
if event == "UI_SCALE_CHANGED" then
self.mode = nil; --to recalculate scale
end
end
local CollapsibleCategory = {
onUpdate = function(self, elapsed)
self.t = self.t + elapsed;
local w = inOutSine(self.t, self.fromW, self.toW, self.d);
if self.t >= self.d then
w = self.toW;
self:SetScript("OnUpdate", nil);
end
self.frame:SetWidth(w);
end
};
function CollapsibleCategory:Init()
if not self.f then
self.f = CreateFrame("Frame", nil, MainFrame);
self.f.frame = MainFrame.CategoryFrame;
end
self.f.fromW = self.f.frame:GetWidth();
self.f.t = 0;
self.f.d = 0.5;
end
function CollapsibleCategory:Collapse()
self:Init();
self.f.toW = self.collapsedWidth;
self.f:SetScript("OnUpdate", self.onUpdate);
end
function CollapsibleCategory:Expand()
self:Init();
self.f.toW = SHRIKNED_LEFT_WIDTH;
self.f:SetScript("OnUpdate", self.onUpdate);
end
function CollapsibleCategory:SetCollapsedWidth(width)
self.collapsedWidth = width;
end
local function MouseoverTracker_OnUpdate(self, elapsed)
self.t1 = self.t1 + elapsed;
if self.t1 > 0.1 then
self.t1 = 0;
else
return
end
if self.CategoryFrame:IsMouseOver() then
if not self.cursorInCategoryFrame then
self.cursorInCategoryFrame = true;
CollapsibleCategory:Expand();
end
else
if self.cursorInCategoryFrame then
self.cursorInCategoryFrame = nil;
CollapsibleCategory:Collapse();
end
end
end
function NarciSettingsFrameMixin:AnchorToInterfaceOptions()
local container = NarciInterfaceOptionsPanel;
if not container then return end;
self:ClearAllPoints();
self:SetParent(container);
local padding = 4;
self:SetPoint("TOPRIGHT", container, "TOPRIGHT", -padding, -padding);
local containerScale = container:GetEffectiveScale();
local containerHeight = container:GetHeight();
local containerWidth = container:GetWidth();
local scale = self:GetScale();
local effectiveSettingsFrameWidth = (MAX_SCROLLFRAME_WIDTH + SHRIKNED_LEFT_WIDTH) * scale;
local exceed = effectiveSettingsFrameWidth - containerWidth * containerScale;
if exceed > 0 then
local collapsedCateWidth = SHRIKNED_LEFT_WIDTH - exceed/containerScale;
if collapsedCateWidth < 36 then
collapsedCateWidth = 36;
end
CollapsibleCategory:SetCollapsedWidth(collapsedCateWidth);
self.CategoryFrame:SetWidth(collapsedCateWidth);
self.t1 = 0;
self:SetScript("OnUpdate", MouseoverTracker_OnUpdate);
else
self.CategoryFrame:SetWidth(SHRIKNED_LEFT_WIDTH);
self:SetScript("OnUpdate", nil);
end
self:SetSize( (containerWidth-2*padding) *containerScale/scale, (containerHeight - 2*padding) *containerScale/scale);
local scrollFrameWidth = self.ScrollFrame:GetWidth();
self.ScrollFrame.ScrollChild:SetWidth(scrollFrameWidth);
self.CloseButton:Hide();
self.BackgroundFrame:Hide();
self.BorderFrame:Hide();
if self.Background then
self.Background:Show();
end
UpdateAlignment();
end
function NarciSettingsFrameMixin:AnchorToDefault()
self:ClearAllPoints();
self:SetParent(nil);
local x, y = Narci_VirtualLineCenter:GetCenter();
local scale = self:GetEffectiveScale();
self:SetPoint("CENTER", UIParent, "LEFT", x/scale, 0);
self:SetSize(DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT);
self.CategoryFrame:SetWidth(DEFAULT_LEFT_WIDTH);
self.ScrollFrame.ScrollChild:SetWidth(DEFAULT_FRAME_WIDTH - DEFAULT_LEFT_WIDTH);
self.CloseButton:Show();
self.BackgroundFrame:Show();
self.BorderFrame:Show();
if self.Background then
self.Background:Hide();
end
UpdateAlignment();
end
---- Slider ----
function SliderUpdator:Stop()
self:SetScript("OnUpdate", nil);
self.cursorX = nil;
self.ratio = nil;
self.slider = nil;
self.left = nil;
self.t = nil;
self.delay = nil;
self.cursorScale = nil;
self.reciprocal = nil;
end
local function SliderUpdator_OnUpdate(self, elapsed)
self.t = self.t + elapsed;
if self.t > 0 then
self.t = self.delay;
else
return
end
local cursorX = GetCursorPosition();
cursorX = cursorX * self.cursorScale - self.cursorOffset;
if cursorX ~= self.cursorX then
self.cursorX = cursorX;
self.ratio = (self.cursorX - self.left) * self.reciprocal;
self.slider:SetValueByRatio(self.ratio, true);
end
end
function SliderUpdator:Start(slider)
self:SetScript("OnUpdate", nil);
self.left = slider:GetEffectiveLeft();
if not self.left then
return
end
self.width = slider:GetEffectiveWidth();
self.reciprocal = 1/self.width;
self.cursorX = GetCursorPosition();
self.t = 1;
self.slider = slider;
local scale = slider:GetEffectiveScale();
self.cursorScale = 1 / scale;
if slider.Thumb:IsMouseOver(0, 0, -2, 2) then
local centerX = slider.Thumb:GetCenter();
local cursorX = GetCursorPosition();
self.cursorOffset = cursorX/scale - centerX;
else
self.cursorOffset = 0;
end
if slider.obeyStep then
self.delay = -0.1;
else
self.delay = -0.016;
end
self:SetScript("OnUpdate", SliderUpdator_OnUpdate);
end
NarciSettingsFrameSliderMixin = {};
function NarciSettingsFrameSliderMixin:OnLoad()
self.BarTexture:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Slider");
self.Thumb:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Slider");
self.Selection:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Slider");
self.Highlight:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Slider");
self.BackgroundLeft:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\SliderBackground");
self.BackgroundCenter:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\SliderBackground");
self.BackgroundRight:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\SliderBackground");
self.valueOffsetRatio = 1;
self:SetSideOffset(4); --half of thumb size
self:SetMinMaxValues(0, 1);
self:SetValue(0);
SetTextureColorByID(self.Thumb, 2);
end
function NarciSettingsFrameSliderMixin:SetValue(value, userInput)
if self.maxVal and value > self.maxVal then
value = self.maxVal;
elseif self.minVal and value < self.minVal then
value = self.minVal;
end
self.value = value;
self.Thumb:SetPoint("CENTER", self.Bar, "LEFT", self.sideOffset + self.valueOffsetRatio * (value - self.minVal), 0);
if self.valueFormatFunc then
self.ValueText:SetText(self.valueFormatFunc(value));
else
self.ValueText:SetText(Round1(value));
end
if userInput and self.onValueChangedFunc then
if self.convertionFunc then
value = self.convertionFunc(value);
end
if value ~= self.lastValue then
self.lastValue = value;
if self.key then
DB[self.key] = value;
end
self.onValueChangedFunc(self, value);
end
end
end
function NarciSettingsFrameSliderMixin:SetValueByRatio(ratio, userInput)
if ratio < 0 then
self:SetValue(self.minVal, userInput);
elseif ratio > 1 then
self:SetValue(self.maxVal, userInput);
else
if self.obeyStep then
local rawValue = ratio * self.range;
local rawStep = math.floor(rawValue / self.valueStep);
local prev = rawStep * self.valueStep;
local next = prev + self.valueStep;
if rawValue > (next + prev) * 0.5 then
rawValue = next;
else
rawValue = prev;
end
self:SetValue(self.minVal + rawValue, userInput);
else
self:SetValue(self.minVal + ratio * self.range, userInput);
end
end
end
function NarciSettingsFrameSliderMixin:SetValueStep(valueStep)
self.valueStep = valueStep;
end
function NarciSettingsFrameSliderMixin:SetMinMaxValues(minVal, maxVal)
self.minVal = minVal;
self.maxVal = maxVal;
self.range = maxVal - minVal;
end
function NarciSettingsFrameSliderMixin:GetRange()
return self.range or 0
end
function NarciSettingsFrameSliderMixin:SetSideOffset(offset)
self.sideOffset = offset;
end
function NarciSettingsFrameSliderMixin:GetEffectiveLeft()
return self:GetLeft() + self.sideOffset;
end
function NarciSettingsFrameSliderMixin:GetEffectiveWidth()
return self:GetWidth() - 2 * self.sideOffset;
end
function NarciSettingsFrameSliderMixin:SetObeyStepOnDrag(state)
if not self.nodes then
self.nodes = {};
end
if state and self.valueStep and self.valueStep > 0 then
local numSteps = Round0( (self.maxVal - self.minVal) / self.valueStep + 1);
if numSteps < 2 then
self:SetObeyStepOnDrag(false);
return
end
self.obeyStep = true;
self.ratioStep = 0.5/numSteps;
for i = 1, numSteps do
if not self.nodes[i] then
self.nodes[i] = self:CreateTexture(nil, "ARTWORK");
self.nodes[i]:SetSize(24, 24);
self.nodes[i]:SetPoint("CENTER", self.Bar, "LEFT", 0, 0);
self.nodes[i]:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Slider");
SetTextureColorByID(self.nodes[i], 1);
end
self.nodes[i]:SetTexCoord(0.125, 0.1875, 0, 0.5);
self.nodes[i]:Show();
end
for i = numSteps + 1, #self.nodes do
self.nodes[i]:Hide();
end
self.numSteps = numSteps;
--self.Bar:SetVertexColor(0.25, 0.25, 0.25);
SetTextureColorByID(self.BarTexture, 1);
else
self.obeyStep = nil;
self.numSteps = 2;
for i = 1, 2 do
if not self.nodes[i] then
self.nodes[i] = self:CreateTexture(nil, "ARTWORK");
self.nodes[i]:SetSize(24, 24);
self.nodes[i]:SetPoint("CENTER", self.Bar, "LEFT", 0, 0);
self.nodes[i]:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Slider");
SetTextureColorByID(self.nodes[i], 1);
end
if i == 1 then
self.nodes[i]:SetTexCoord(0.25, 0.3125, 0, 0.5);
else
self.nodes[i]:SetTexCoord(0.3125, 0.375, 0, 0.5);
end
self.nodes[i]:Hide();
end
for i = 3, #self.nodes do
self.nodes[i]:Hide();
end
SetTextureColorByID(self.BarTexture, 1);
end
self:OnSizeChanged();
end
function NarciSettingsFrameSliderMixin:OnSizeChanged()
local width = self:GetWidth();
if width and self.numSteps then
if self.numSteps > 2 then
local effectiveWidth = width - self.sideOffset * 2;
local gap = effectiveWidth / (self.numSteps - 1);
for i = 1, self.numSteps do
self.nodes[i]:ClearAllPoints();
self.nodes[i]:SetPoint("CENTER", self.Bar, "LEFT", self.sideOffset + (i - 1) * gap, 0);
end
else
self.nodes[1]:ClearAllPoints();
self.nodes[1]:SetPoint("CENTER", self.Bar, "LEFT", self.sideOffset, 0);
self.nodes[2]:ClearAllPoints();
self.nodes[2]:SetPoint("CENTER", self.Bar, "RIGHT", -self.sideOffset, 0);
end
width = width - 4;
local pixelScale = 0.75;
local pixelWidth = width / pixelScale;
if pixelWidth > 512 then
pixelWidth = 512;
end
local coord = (pixelWidth / 512) * 0.5;
if self.obeyStep then
self.BarTexture:SetTexCoord(0.5 - coord, 0.5 + coord, 0.75, 1);
else
self.BarTexture:SetTexCoord(0.5 - coord, 0.5 + coord, 0.5, 0.75);
end
self.valueOffsetRatio = self:GetEffectiveWidth() / self:GetRange();
end
end
function NarciSettingsFrameSliderMixin:OnMouseDown()
SliderUpdator:Start(self);
self.isDragging = true;
end
function NarciSettingsFrameSliderMixin:OnMouseUp()
SliderUpdator:Stop();
self.isDragging = nil;
if not self:IsFocused() then
self:HighlightFrame(false);
end
end
function NarciSettingsFrameSliderMixin:IsFocused()
return (self:IsVisible() and self:IsMouseOver(0, 0, -12, 12))
end
function NarciSettingsFrameSliderMixin:SetSliderWidth(width, adjustOffsetByLabelWidth)
self:SetWidth(width);
if adjustOffsetByLabelWidth then
local labelWidth = self:GetParent().Label:GetWrappedWidth();
if labelWidth then
self:SetPoint("LEFT", self:GetParent(), "LEFT", labelWidth + 64, 0);
end
end
--local offsetX = 120 - 192 + width + 16;
--self:SetPoint("LEFT", self:GetParent(), "LEFT", offsetX, 0);
self:OnSizeChanged();
end
function NarciSettingsFrameSliderMixin:OnEnter()
self:HighlightFrame(true);
end
function NarciSettingsFrameSliderMixin:OnLeave()
if not self.isDragging then
self:HighlightFrame(false);
end
end
function NarciSettingsFrameSliderMixin:HighlightFrame(state)
if state then
SetTextColorByID(self:GetParent().Label, 3);
SetTextColorByID(self.ValueText, 3);
SetTextureColorByID(self.BarTexture, 2);
self.Highlight:Show();
else
SetTextColorByID(self:GetParent().Label, 2);
SetTextColorByID(self.ValueText, 2);
SetTextureColorByID(self.BarTexture, 1);
self.Highlight:Hide();
end
end
function NarciSettingsFrameSliderMixin:UpdateState()
if self.key and DB[self.key] then
if self.convertionFunc then
self:SetValue( self.convertionFunc(DB[self.key]) );
else
self:SetValue(DB[self.key]);
end
elseif self.getValueFunc then
self:SetValue( self.getValueFunc() );
else
if self.minVal then
self:SetValue(self.minVal);
end
end
end
---- Keybindings ----
local function KeybingdingButton_OnEvent(self, event, ...)
if event == "GLOBAL_MOUSE_DOWN" then
if not self:IsFocused() then
self:StopListening();
end
end
end
NarciSettingsKeybindingButton = {};
function NarciSettingsKeybindingButton:OnLoad()
self.Left:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Keybinding");
self.Center:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Keybinding");
self.Right:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\Keybinding");
self.BGLeft:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\KeybindingBackground");
self.BGCenter:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\KeybindingBackground");
self.BGRight:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\KeybindingBackground");
self.TextBackground:SetColorTexture(0.92, 0.92, 0.92);
self:OnLeave();
end
function NarciSettingsKeybindingButton:OnEnter()
self:HighlightFrame(true);
SetTextColorByID(self.Label, 3);
end
function NarciSettingsKeybindingButton:OnLeave()
if not self.active then
self:HighlightFrame(false);
end
SetTextColorByID(self.Label, 1);
end
function NarciSettingsKeybindingButton:UpdateState()
local key;
if self.actionName then
key = GetBindingKey(self.actionName);
end
if key then
self:SetText(key);
SetTextColorByID(self.ButtonText, 3);
else
self:SetText(NOT_BOUND);
SetTextColorByID(self.ButtonText, 1);
end
end
function NarciSettingsKeybindingButton:SetExternalAction(actionName)
--Processesd by WoWUI, globally
self.actionName = actionName;
end
function NarciSettingsKeybindingButton:SetInternalAction(actionName)
--Used and processed by Narcissus
self.actionName = actionName;
end
function NarciSettingsKeybindingButton:HighlightFrame(state)
if state then
SetTextureColorByID(self.Left, 2);
SetTextureColorByID(self.Center, 2);
SetTextureColorByID(self.Right, 2);
else
SetTextureColorByID(self.Left, 1);
SetTextureColorByID(self.Center, 1);
SetTextureColorByID(self.Right, 1);
end
end
function NarciSettingsKeybindingButton:OnClick(mouseButton)
if mouseButton == "RightButton" then
self:ClearBinding();
else
if self.active then
self:StopListening();
else
self:StartListening();
end
end
end
local RESERVED_KEYS = {
ESCAPE = true,
BACKSPACE = true,
SPACE = true,
ENTER = true,
TAB = true,
};
local function ClearBindingKey(actionName)
local key1, key2 = GetBindingKey(actionName);
if key1 then
SetBinding(key1, nil, 1);
end
if key2 then
SetBinding(key2, nil, 1);
end
SaveBindings(1);
end
local function ExternalAction_OnKeydown(self, key)
if key == "ESCAPE" then
self:StopListening();
return
end
if RESERVED_KEYS[key] then
self:ExitAndShowInvalidKey(key);
return
end
local keyString = CreateKeyChordStringUsingMetaKeyState(key);
self.newKey = keyString;
--self.ButtonText:SetText(keyString);
self:AnimateSetText(keyString);
if not IsKeyPressIgnoredForBinding(key) then
self:AttemptToBind();
end
end
local function ExternalAction_OnKeyUp(self, key)
self:AttemptToBind();
end
function NarciSettingsKeybindingButton:StartListening()
self.active = true;
self.ButtonText:SetTextColor(0, 0, 0);
self.ButtonText:SetShadowColor(1, 1, 1);
self.ButtonText:SetShadowOffset(0, 0);
self.ButtonText.AnimInput:Stop();
self.TextBackground.AnimFadeOut:Stop();
self.TextBackground:SetColorTexture(0.92, 0.92, 0.92);
self.TextBackground:Show();
self:SetScript("OnEvent", KeybingdingButton_OnEvent);
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
SCROLL_LOCKED = true;
MainFrame.ScrollFrame:LockScroll(true);
MainFrame.ScrollFrame:ScrollToWidget(self, 24);
self:SetScript("OnKeyDown", ExternalAction_OnKeydown);
self:SetScript("OnKeyUp", ExternalAction_OnKeyUp);
self:SetPropagateKeyboardInput(false);
if GAMEPAD_ENABLED then
end
end
function NarciSettingsKeybindingButton:StopListening()
self.active = nil;
self:SetScript("OnKeyDown", nil);
self:SetScript("OnKeyUp", nil);
if GAMEPAD_ENABLED then
self:SetScript("OnGamePadButtonDown", nil);
self:SetScript("OnGamePadButtonUp", nil);
end
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
if not self:IsFocused() then
self:HighlightFrame(false);
end
if not self.TextBackground.AnimFadeOut:IsPlaying() then
self.TextBackground:Hide();
end
self.ButtonText:SetShadowColor(0, 0, 0);
self.ButtonText:SetShadowOffset(1, -1);
self:UpdateState();
SCROLL_LOCKED = false;
MainFrame.ScrollFrame:LockScroll(false);
AlertMessageFrame:Hide();
end
function NarciSettingsKeybindingButton:AnimateSetText(text)
self.ButtonText.AnimInput:Stop();
local width1 = self.ButtonText:GetWrappedWidth();
self.ButtonText:SetText(text);
local width2 = self.ButtonText:GetWrappedWidth();
local diff = 0.5*(width2 - width1);
if diff > 10 or diff <-10 then
diff = 0;
end
self.ButtonText.AnimInput.X1:SetOffset(diff, 0);
self.ButtonText.AnimInput.X2:SetOffset(-diff, 0);
self.ButtonText.AnimInput:Play();
end
function NarciSettingsKeybindingButton:ClearBinding()
ClearBindingKey(self.actionName);
self:StopListening();
end
function NarciSettingsKeybindingButton:OnHide()
if self.active then
self:StopListening();
end
end
function NarciSettingsKeybindingButton:IsFocused()
return self:IsMouseOver() and self:IsVisible();
end
function NarciSettingsKeybindingButton:ExitAndShowInvalidKey(key)
self:StopListening();
AlertMessageFrame:ShowInvalidKey(self, key);
end
function NarciSettingsKeybindingButton:AttemptToBind(override)
self:SetScript("OnKeyDown", nil);
self:SetScript("OnKeyUp", nil);
if GAMEPAD_ENABLED then
self:SetScript("OnGamePadButtonDown", nil);
self:SetScript("OnGamePadButtonUp", nil);
end
if not self.newKey then
self:StopListening();
return
end
if IsKeyPressIgnoredForBinding(self.newKey) then
self:ExitAndShowInvalidKey(self.newKey);
return
end
local action = GetBindingAction(self.newKey);
if (action and action ~= "" and action ~= self.actionName) and not override then
AlertMessageFrame:ShowOverwriteConfirmation(self, action);
return
else
ClearBindingKey(self.actionName);
if SetBinding(self.newKey, self.actionName, 1) then
--Successful
self.TextBackground.AnimFadeOut:Stop();
self.TextBackground:SetColorTexture(0.35, 0.61, 0.38); --green
self.TextBackground.AnimFadeOut:Play();
self:StopListening();
SaveBindings(1); --account wide
return true
else
self:StopListening();
return
end
end
end
local ClipboardUtil = {};
ClipboardUtil.scripts = {};
function ClipboardUtil:CreateClipboard()
Clipboard = CreateFrame("EditBox", nil, MainFrame);
Clipboard:SetFontObject("NarciFontMedium13");
Clipboard:SetShadowOffset(0, 0);
Clipboard:SetTextInsets(6, 6, 0, 0);
Clipboard:SetAutoFocus(false);
Clipboard:SetHighlightColor(0, 0.35, 0.75);
Clipboard:SetJustifyH("CENTER");
Clipboard:SetPropagateKeyboardInput(false);
for name, method in pairs(self.scripts) do
Clipboard:SetScript(name, method);
end
SetTextColorByID(Clipboard, 3);
end
function ClipboardUtil:SetupFromWebsiteButton(websiteButton)
if not Clipboard then
self:CreateClipboard();
end
Clipboard:ClearAllPoints();
Clipboard:SetParent(websiteButton);
Clipboard:SetPoint("TOPLEFT", websiteButton, "TOPLEFT", 0, 0);
Clipboard:SetPoint("BOTTOMRIGHT", websiteButton, "BOTTOMRIGHT", 0, 0);
Clipboard:Show();
Clipboard:SetText(websiteButton.link);
Clipboard:SetCursorPosition(0);
Clipboard:SetFocus();
end
function ClipboardUtil.scripts.OnKeyDown(self, key)
local keys = CreateKeyChordStringUsingMetaKeyState(key);
if keys == "CTRL-C" or key == "COMMAND-C" then
AboutTab.projectHeader.animSuccess:Play();
AboutTab.projectHeader:SetText(L["Copied"]);
self:Hide();
end
end
function ClipboardUtil.scripts.OnEditFocusLost(self)
if self:IsShown() then
self:HighlightText(0, 0);
if IsMouseButtonDown() then
for _, button in ipairs(AboutTab.websiteButtons) do
if button:IsMouseOver() then
return
end
end
end
self:Hide();
end
end
function ClipboardUtil.scripts.OnEditFocusGained(self)
self:HighlightText();
end
function ClipboardUtil.scripts.OnHide(f)
AboutTab:UpdateWebsiteButtons();
f:Hide();
end
function ClipboardUtil.scripts.OnEscapePressed(self)
self:Hide();
end
function ClipboardUtil.scripts.OnEnterPressed(self)
self:Hide();
end
function ClipboardUtil.scripts.OnTextChanged(self, userInput)
if userInput then
self:Hide();
end
end
function ClipboardUtil.scripts.OnCursorChanged(self)
self:HighlightText();
end
NarciSettingsClipboardButtonMixin = {};
function NarciSettingsClipboardButtonMixin:OnLoad()
self.Left:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\EditBox");
self.Center:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\EditBox");
self.Right:SetTexture("Interface\\AddOns\\Narcissus\\Art\\SettingsFrame\\EditBox");
self:HighlightFrame(false);
end
function NarciSettingsClipboardButtonMixin:OnClick()
if self.isActive then
self.isActive = nil;
AboutTab:UpdateWebsiteButtons();
else
self:PlaceClipboard();
end
end
function NarciSettingsClipboardButtonMixin:OnEnter()
self:HighlightFrame(true);
end
function NarciSettingsClipboardButtonMixin:OnLeave()
self:HighlightFrame(false);
end
function NarciSettingsClipboardButtonMixin:HighlightFrame(state)
if self.isActive then return end;
if state then
SetTextureColorByID(self.Left, 2);
SetTextureColorByID(self.Center, 2);
SetTextureColorByID(self.Right, 2);
SetTextureColorByID(self.Logo, 3);
SetTextColorByID(self.ButtonText, 3);
else
SetTextureColorByID(self.Left, 1);
SetTextureColorByID(self.Center, 1);
SetTextureColorByID(self.Right, 1);
SetTextureColorByID(self.Logo, 2);
SetTextColorByID(self.ButtonText, 2);
end
end
function NarciSettingsClipboardButtonMixin:OnMouseDown()
self.ButtonText:SetPoint("CENTER", self, "CENTER", 16, -0.8);
if self.logoMode then
self.Logo:SetPoint("CENTER", self, "CENTER", 0, -0.8);
end
end
function NarciSettingsClipboardButtonMixin:OnMouseUp()
self.ButtonText:SetPoint("CENTER", self, "CENTER", 16, 0);
if self.logoMode then
self.Logo:SetPoint("CENTER", self, "CENTER", 0, 0);
end
if Clipboard and Clipboard:IsShown() then
Clipboard:SetFocus();
end
end
function NarciSettingsClipboardButtonMixin:SetLogoOnlyMode(state)
self.Logo:ClearAllPoints();
if state then
self.ButtonText:Hide();
self.Logo:SetPoint("CENTER", self, "CENTER", 0, 0);
else
self.ButtonText:Show();
self.Logo:SetPoint("RIGHT", self.ButtonText, "LEFT", -4, 0);
end
self.Logo:Show();
self.logoMode = state;
end
function NarciSettingsClipboardButtonMixin:PlaceClipboard()
AboutTab:UpdateWebsiteButtons(self.id);
self.Logo:Hide();
self.ButtonText:Hide();
self.Left:SetVertexColor(0, 0.5, 0.83);
self.Center:SetVertexColor(0, 0.5, 0.83);
self.Right:SetVertexColor(0, 0.5, 0.83);
self.isActive = true;
ClipboardUtil:SetupFromWebsiteButton(self);
end
NarciSettingsAlertMessageFrameMixin = {};
function NarciSettingsAlertMessageFrameMixin:ShowInvalidKey(keybindingButton, key)
self:AnchorToButton(keybindingButton);
self.YesButton:Hide();
self.NoButton:Hide();
SetTextColorByID(self.Message, 3);
self.Stroke:SetColorTexture(0.75, 0.06, 0);
self.Background:SetColorTexture(0.35, 0.11, 0.11);
self:SetAlertMessage(key.." is invalid");
self:StopAnimating();
self.AnimFadeIn:Play();
self:Show();
end
function NarciSettingsAlertMessageFrameMixin:ShowOverwriteConfirmation(keybindingButton, conflictedAction)
self:AnchorToButton(keybindingButton);
local actionName = GetBindingName(conflictedAction);
SetTextColorByID(self.Message, 3);
self.Stroke:SetColorTexture(0.4, 0.4, 0.4);
self.Background:SetColorTexture(0.08, 0.08, 0.08);
self.YesButton:Show();
self.NoButton:Show();
self.NoButton.Countdown:SetCooldown(GetTime(), 8);
self:SetAlertMessage("Override "..actionName.." ?");
self:StopAnimating();
self.AnimShake:Play();
self:Show();
self.parentButton = keybindingButton;
keybindingButton.TextBackground:SetColorTexture(1, 0.82, 0);
end
function NarciSettingsAlertMessageFrameMixin:ShowRequiresReload()
self:StopAnimating();
self.YesButton:Hide();
self.NoButton:Hide();
self:ClearAllPoints();
self:SetParent(MainFrame.ScrollFrame);
self:SetPoint("TOP", MainFrame.ScrollFrame, "TOP", 0, -8);
self:SetAlertMessage(REQUIRES_RELOAD or "Requires Reload");
self.Message:SetTextColor(1, 0.93, 0);
self.Stroke:SetColorTexture(0.4, 0.4, 0.4);
self.Background:SetColorTexture(0.08, 0.08, 0.08);
self.AnimFadeIn:Play();
self:Show();
end
function NarciSettingsAlertMessageFrameMixin:AnchorToButton(keybindingButton)
self:ClearAllPoints()
--self:SetPoint("BOTTOM", keybindingButton, "TOP", 0, 4);
self:SetPoint("TOP", keybindingButton, "BOTTOM", 0, -8);
self:SetParent(keybindingButton);
end
function NarciSettingsAlertMessageFrameMixin:SetAlertMessage(msg)
self.Message:SetText(msg);
local width = self.Message:GetWrappedWidth();
local height = self.Message:GetHeight();
if self.YesButton:IsShown() then
self:SetSize(Round0(width + 32), Round0(height + 16 + 32 + 2));
else
self:SetSize(Round0(width + 20), Round0(height + 20));
end
--Update alignment
if self:GetBottom() < MainFrame.ScrollFrame:GetBottom() then
self:ClearAllPoints();
self:SetPoint("BOTTOM", self:GetParent(), "TOP", 0, 8);
end
end
function NarciSettingsAlertMessageFrameMixin:OnHide()
self:Hide();
self.NoButton.Countdown:Clear();
end
local function AlertFrameButton_OnEnter(self)
self.Texture:SetVertexColor(1, 1, 1);
if self.Countdown then
self.Countdown:Pause();
end
end
local function AlertFrameButton_OnLeave(self)
self.Texture:SetVertexColor(0.67, 0.67, 0.67);
if self.Countdown then
self.Countdown:Resume();
end
end
local function AlertFrameButton_OnMouseDown(self)
self.Texture:SetScale(0.8);
end
local function AlertFrameButton_OnMouseUp(self)
self.Texture:SetScale(1);
end
local function AlertFrameButton_Yes_OnClick(self)
self:GetParent():Hide();
self:GetParent().parentButton:AttemptToBind(true);
end
local function AlertFrameButton_No_OnClick(self)
self:GetParent():Hide();
end
local function Countdown_OnFinished()
AlertMessageFrame:Hide();
local keybindingButton = AlertMessageFrame:GetParent();
if keybindingButton and keybindingButton.StopListening then
keybindingButton:StopListening();
end
end
function NarciSettingsAlertMessageFrameMixin:OnLoad()
AlertMessageFrame = self;
self.YesButton:SetScript("OnEnter", AlertFrameButton_OnEnter);
self.YesButton:SetScript("OnLeave", AlertFrameButton_OnLeave);
self.YesButton:SetScript("OnMouseDown", AlertFrameButton_OnMouseDown);
self.YesButton:SetScript("OnMouseUp", AlertFrameButton_OnMouseUp);
self.YesButton:SetScript("OnClick", AlertFrameButton_Yes_OnClick);
self.NoButton:SetScript("OnEnter", AlertFrameButton_OnEnter);
self.NoButton:SetScript("OnLeave", AlertFrameButton_OnLeave);
self.NoButton:SetScript("OnMouseDown", AlertFrameButton_OnMouseDown);
self.NoButton:SetScript("OnMouseUp", AlertFrameButton_OnMouseUp);
self.NoButton:SetScript("OnClick", AlertFrameButton_No_OnClick);
self.NoButton.Countdown:SetScript("OnCooldownDone", Countdown_OnFinished);
self.Stroke:SetColorTexture(0.4, 0.4, 0.4);
self.Exclusion:SetTexture("Interface\\AddOns\\Narcissus\\Art\\Masks\\Exclusion", "CLAMPTOWHITE", "CLAMPTOWHITE", "LINEAR");
end
function NarciSettingsAlertMessageFrameMixin:OnShow()
local a = NarciAPI.GetPixelForWidget(self, 2);
self.Exclusion:ClearAllPoints();
self.Exclusion:SetPoint("TOPLEFT", self, "TOPLEFT", a, -a);
self.Exclusion:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -a, a);
end
local function GetSettingsButtonByDBKey(dbKey)
for id, button in ipairs(OptionButtons) do
if button.key == dbKey then
return button
end
end
end
NarciAPI.GetSettingsButtonByDBKey = GetSettingsButtonByDBKey;
function Narci_PreferenceButton_OnClick(self)
MainFrame:ToggleUI();
end