local _, addon = ... local API = addon.API; local TooltipFrame = addon.SharedTooltip; local Clamp = API.Clamp; local GetCursorPosition = GetCursorPosition; --widgets are created on-use local FRAME_WIDTH = 480; local FRAME_HEIGHT = 480 local FRAME_INSET = 12; local EDITBOX_TEXT_INSET = 4; local SCROLLBAR_WIDTH = 12; local Clipboard = CreateFrame("Frame"); addon.Clipboard = Clipboard; Clipboard:Hide(); Clipboard:EnableMouse(true); Clipboard:SetToplevel(true); local CopyTextButtons = {}; local EditBoxMixin = {}; do function EditBoxMixin:OnTextChanged(userInput) if userInput then Clipboard:Hide(); return end C_Timer.After(0, function() self:GetParent():UpdateScrollChildRect(); --? self:GetParent():UpdateScrollRange(); end); end function EditBoxMixin:OnEscapePressed() Clipboard:Hide(); end function EditBoxMixin:OnEditFocusGained() end function EditBoxMixin:OnEditFocusLost() end end local ScrollFrameMixin = {}; do local OFFSET_PER_SCROLL = 24; --two lines function ScrollFrameMixin:SetScrollOffset(scrollOffset) scrollOffset = Clamp(scrollOffset, 0, self.range); self.scrollOffset = scrollOffset; self:SetVerticalScroll(scrollOffset); self.scrollBar:UpdateThumbPosition(); end function ScrollFrameMixin:ScrollBy(offset) self:SetScrollOffset(self:GetVerticalScroll() + offset) end function ScrollFrameMixin:OnMouseWheel(delta) if delta > 0 then self:ScrollBy(-OFFSET_PER_SCROLL); else self:ScrollBy(OFFSET_PER_SCROLL); end end function ScrollFrameMixin:ScrollToTop() self:SetScrollOffset(0); end function ScrollFrameMixin:ScrollToBottom() self:SetScrollOffset(self:GetVerticalScrollRange()); end function ScrollFrameMixin:UpdateScrollRange() local range = self:GetVerticalScrollRange(); if range <= 0 then range = 0; self.scrollBar:Hide(); else self.scrollBar:Show(); end local diff = self.range and (self.range - range) or 0; local resetScrollOffset = diff < -1 or diff > 1; self.range = range; self.scrollBar:UpdateThumbSize(); if resetScrollOffset then self:ScrollToTop(); end end function ScrollFrameMixin:SetScrollBar(scrollBar) self.scrollBar = scrollBar; scrollBar:SetOwner(self); end function ScrollFrameMixin:GetScrollOffset() return self.scrollOffset or self:GetVerticalScroll(); end function ScrollFrameMixin:GetScrollRange() return self.range or self:GetVerticalScrollRange() end function ScrollFrameMixin:GetViewSize() return self:GetHeight() end end function Clipboard:StartCursorScrolling() self.cursorTop = self:GetTop() - FRAME_INSET; self.cursorBottom = self:GetBottom() + FRAME_INSET; self.t = 0; self.interval = 0.25; self:SetScript("OnUpdate", self.OnUpdate); end function Clipboard:StopCursorScrolling() self:SetScript("OnUpdate", nil); self.t = nil; end function Clipboard:OnUpdate(elapsed) self.t = self.t + elapsed; if self.t >= self.interval then local delta; local _, cursorY = GetCursorPosition(); if cursorY > self.cursorTop then if self.t > 0.25 then self.t = elapsed; end delta = (self.cursorTop - cursorY) * self.t * 10; self.interval = 0.016; elseif cursorY < self.cursorBottom then if self.t > 0.25 then self.t = elapsed; end delta = (self.cursorBottom - cursorY) * self.t * 10; self.interval = 0.016; else self.interval = 0.5; end self.t = 0; if delta then self.ScrollFrame:ScrollBy(delta); end end end function Clipboard:Init() self:SetSize(FRAME_WIDTH, FRAME_HEIGHT); self:SetPoint("CENTER", UIParent, "CENTER", 0, 0); self:SetFrameStrata("DIALOG"); local bg = self:CreateTexture(nil, "BACKGROUND"); bg:SetAllPoints(true); local corner = 16; bg:SetTextureSliceMargins(corner, corner, corner, corner); bg:SetTextureSliceMode(1); bg:SetTexture("Interface/AddOns/DialogueUI/Art/Theme_Shared/ClipboardBackground.png"); API.UpdateTextureSliceScale(bg); local ScrollBar = addon.CreateScrollBar(self); self.ScrollBar = ScrollBar; ScrollBar:SetPoint("TOPRIGHT", self, "TOPRIGHT", -FRAME_INSET, -FRAME_INSET); ScrollBar:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -FRAME_INSET, FRAME_INSET); ScrollBar:SetAlwaysVisible(true); ScrollBar:SetTheme(2); ScrollBar:Show(); local ScrollFrame = CreateFrame("ScrollFrame", nil, self); self.ScrollFrame = ScrollFrame; ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT", FRAME_INSET, -FRAME_INSET); ScrollFrame:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", -(FRAME_INSET + SCROLLBAR_WIDTH + FRAME_INSET), FRAME_INSET); local EditBox = CreateFrame("EditBox", nil, ScrollFrame); self.EditBox = EditBox; local eidtBoxWidth = FRAME_WIDTH - 3*FRAME_INSET - SCROLLBAR_WIDTH; EditBox:SetFontObject("DUIFont_Quest_Quest"); --EditBox:SetTextColor(1, 1, 1); EditBox:SetAutoFocus(false); EditBox:SetMultiLine(true); --EditBox:SetVisibleTextByteLimit(32); --Not just being invisible, but truncated EditBox:SetHighlightColor(0, 0.471, 0.843); EditBox:SetPoint("TOPLEFT"); EditBox:SetWidth(eidtBoxWidth) EditBox:SetHeight(1); EditBox:SetTextInsets(EDITBOX_TEXT_INSET, EDITBOX_TEXT_INSET, EDITBOX_TEXT_INSET, EDITBOX_TEXT_INSET); ScrollFrame:SetScrollChild(EditBox); API.Mixin(EditBox, EditBoxMixin); EditBox:SetScript("OnTextChanged", EditBox.OnTextChanged); EditBox:SetScript("OnEscapePressed", EditBox.OnEscapePressed); API.Mixin(ScrollFrame, ScrollFrameMixin); ScrollFrame:SetScript("OnMouseWheel", ScrollFrame.OnMouseWheel); ScrollFrame:SetScrollBar(ScrollBar); self.Init = nil; end function Clipboard:ShowContent(text, senderCopyButton) if self.Init then self:Init(); end self.EditBox:SetText(text); self:Show(); self.sender = senderCopyButton; end function Clipboard:IsFromSameSender(sender) return self.sender and self.sender == sender end function Clipboard:CloseIfFromSameSender(sender) if self:IsFromSameSender(sender) then self:Hide(); return true end end function Clipboard:OnShow() self:RegisterEvent("GLOBAL_MOUSE_DOWN"); self:RegisterEvent("GLOBAL_MOUSE_UP"); end Clipboard:SetScript("OnShow", Clipboard.OnShow); function Clipboard:OnEvent(event, ...) if event == "GLOBAL_MOUSE_DOWN" then if self:IsMouseOver() then if self.EditBox:IsMouseOver() then self:StartCursorScrolling(); end else for i, button in ipairs(CopyTextButtons) do if button:IsMouseOver() then return end end self:Hide(); end elseif event == "GLOBAL_MOUSE_UP" then self:StopCursorScrolling(); end end Clipboard:SetScript("OnEvent", Clipboard.OnEvent); function Clipboard:OnHide() self.sender = nil; self:UnregisterEvent("GLOBAL_MOUSE_DOWN"); self:UnregisterEvent("GLOBAL_MOUSE_UP"); self.EditBox:SetText(""); self.EditBox:ClearHighlightText(); self:StopCursorScrolling(); end Clipboard:SetScript("OnHide", Clipboard.OnHide); do --Copy Text Button local BUTTON_SIZE = 24; local ICON_SIZE = 16; local ALPHA_UNFOCUSED = 0.6; local CopyTextButtonMixin = {}; function CopyTextButtonMixin:OnEnter() self.Icon:SetAlpha(1); TooltipFrame:Hide(); TooltipFrame:SetOwner(self, "TOPRIGHT"); TooltipFrame:AddLeftLine(addon.L["Copy Text"], 1, 1, 1); TooltipFrame:Show(); end function CopyTextButtonMixin:OnLeave() self.Icon:SetAlpha(ALPHA_UNFOCUSED); TooltipFrame:Hide(); end function CopyTextButtonMixin:SetTheme(themeID) if themeID == 1 then self.Icon:SetTexCoord(0, 0.5, 0, 1); --Brown, white stroke else self.Icon:SetTexCoord(0.5, 1, 0, 1); --Grey, black stroke end end local function CreateCopyTextButton(parent, onClickFunc, themeID) local b = CreateFrame("Button", nil, parent); b:SetSize(BUTTON_SIZE, BUTTON_SIZE); b.Icon = b:CreateTexture(nil, "OVERLAY"); b.Icon:SetSize(ICON_SIZE, ICON_SIZE); b.Icon:SetPoint("CENTER", b, "CENTER", 0, 0); b.Icon:SetTexture("Interface/AddOns/DialogueUI/Art/Theme_Shared/CopyTextButton.png"); b.Icon:SetAlpha(ALPHA_UNFOCUSED); API.Mixin(b, CopyTextButtonMixin); b:SetScript("OnClick", onClickFunc); b:SetScript("OnEnter", b.OnEnter); b:SetScript("OnLeave", b.OnLeave); b:SetTheme(themeID); table.insert(CopyTextButtons, b); return b end addon.CreateCopyTextButton = CreateCopyTextButton; end