-----------------------------
-- CreateEditBuffer
-----------------------------
local function CreateEditBuffer(name, parent, anchor1, anchor2, fontSize, numLines, lineHeight)
if(not name or not parent) then do return nil end end
local anchor1_default = {TOPLEFT, parent, TOPLEFT, 0, 0}
local anchor2_default = {BOTTOMRIGHT, parent, BOTTOMRIGHT, 0, 0}
-- Optional Parameters
local anchor1 = anchor1 or anchor1_default
local anchor2 = anchor2 or anchor2_default
if(type(anchor1) ~= "table") then anchor1 = anchor1_default end
if(type(anchor2) ~= "table") then anchor2 = anchor2_default end
--'LibDebug/fonts/AnkaCoder-C87-r.ttf' size:17 charwidth: 8.75 | 21 @ 11.5 | 20 @ 10.75
-- Font settings
local FONT_STYLE_THIN = 'soft-shadow-thin'
local FONT_STYLE_THICK = 'soft-shadow-thick'
local FONT_STYLE_SHADOW = 'shadow'
local FONT_STYLE_NONE = 'none'
local FONT_SIZE = fontSize or 20
local FONT_FACE = 'LibDebug/fonts/AnkaCoder-C87-b.ttf'
local CHAR_WIDTH = 10.75
local LINE_HEIGHT = lineHeight or tonumber(FONT_SIZE*1.275)
-- Control-Names
local BG = name..'_BG'
-- BG
WINDOW_MANAGER:CreateControlFromVirtual(BG, parent, "ZO_InsetBackdrop")
_G[BG]:SetAnchor(anchor1[1], anchor1[2], anchor1[3], anchor1[4], anchor1[5])
_G[BG]:SetAnchor(anchor2[1], anchor2[2], anchor2[3], anchor2[4], anchor2[5])
-- LINES (EDIT)
local numLines = numLines or math.floor((_G[BG]:GetHeight()-anchor1[5]-anchor2[5])/LINE_HEIGHT)
for i=1, numLines, 1 do
local LINE = name..'_LINE'..tostring(i)
WINDOW_MANAGER:CreateControlFromVirtual(LINE, parent, "ZO_DefaultEditMultiLineForBackdrop")
_G[LINE]:SetMaxInputChars(1000) -- Hello Windows 98 and FAT, I missed you NOT
_G[LINE]:SetMultiLine(false)
_G[LINE]:SetEditEnabled(false)
_G[LINE]:SetCopyEnabled(true)
_G[LINE]:SetAnchor(TOPLEFT, _G[BG], TOPLEFT, 7, (5+((i-1)*LINE_HEIGHT)))
_G[LINE]:SetDimensions((_G[BG]:GetWidth()-10), LINE_HEIGHT)
_G[LINE]:SetColor(207/255, 220/255, 189/255, 1)
_G[LINE]:SetHandler("OnMouseDoubleClick", function(self)
-- bah
zo_callLater(function() self:SelectAll() end, 0.5)
end)
-- Set monospace font with fixed width
_G[LINE]:SetFont(FONT_FACE..'|'..FONT_SIZE..'|'..FONT_STYLE_THIN)
end
-- Create an empty table / pseudo-control that will hold our public stuff
local control = {}
control.text = "" -- holds the unmodified text
control.offset = 1 -- starts at line 1
local function disable_links(text)
local links = {}
for link in string.gfind(text, "(|H(.-):(.-)|h(.-)|h)") do
local name = link:match("|h%[(.-)%]|h")
if(name) then
links[#links+1] = {["name"] = name, ["link"] = link }
text = str_replace(text, str_escape(link), '['..tostring(name)..']', false)
end
end
return text, links
end
local function enable_links(text, links)
if(not links or type(links) ~= "table") then do return text end end
for i,o in ipairs(links) do
local disabled_link = '['..tostring(o["name"])..']'
text = str_replace(text, str_escape(disabled_link), o["link"], false)
end
return text
end
local function clear_links(links)
for i,o in ipairs(links) do
links[i] = nil
end
links = nil
return nil
end
function control:SetText(text)
self.text = text
self:Clear()
local numLines = self:GetNumCurLines()
local maxLines = self:GetNumMaxLines()
if(numLines > maxLines) then
local offset = numLines-maxLines
self:DisplayLinesAt(offset)
else
self:DisplayLinesAt()
end
end
function control:GetNumCurLines()
local all_lines = self:GetAllLines()
return #all_lines
end
function control:GetNumMaxLines()
return numLines
end
function control:GetAllLines()
local ret = {}
for line in string.gmatch(self.text, "[^\n]+") do
local line, links = disable_links(line)
local real_lines = self:SplitLongLines(line)
for _,r_line in ipairs(real_lines) do
ret[#ret+1] = enable_links(r_line, links)
end
links = clear_links(links)
--all_lines[#all_lines+1] = line
end
enable_links()
return ret
end
function control:DisplayLinesAt(offset)
self:Clear()
local offset = offset or 0
if(offset < 0) then do return end end
local all_lines = self:GetAllLines()
-- output lines
for i=1, numLines, 1 do
local LINE = name..'_LINE'..tostring(i)
if(all_lines[i+offset] and _G[LINE]) then
_G[LINE]:SetText(all_lines[i+offset])
end
end
self.offset = offset
end
function control:ScrollUp()
local numLines = self:GetNumCurLines()
local maxLines = self:GetNumMaxLines()
-- only scroll if theres more text aviable then displayed
if(numLines > maxLines) then
local new_offset = math.floor(control.offset - 1)
if(new_offset >= 0) then self:DisplayLinesAt(new_offset) end
end
end
function control:ScrollDown()
local numLines = self:GetNumCurLines()
local maxLines = self:GetNumMaxLines()
-- only scroll if theres more text aviable then displayed
if(numLines > maxLines) then
local new_offset = math.floor(control.offset + 1)
local displayed_lines = new_offset+maxLines
if(new_offset >= 0 and displayed_lines <= numLines) then control:DisplayLinesAt(new_offset) end
end
end
function control:SplitLongLines(text, maxLength)
local ret = {}
local maxLineWidth = _G[BG]:GetWidth()
local maxChars = maxLength or math.floor(maxLineWidth/CHAR_WIDTH)
local text_len = string.len(text);
if(text_len <= maxChars) then
ret[#ret+1] = text
else
for from = 0, text_len, maxChars do
local to = from+maxChars-1
if(from >= text_len) then from = text_len end
if(to >= text_len) then to = text_len end
--ret = ret+1
ret[#ret+1] = string.sub(text, from, to)
end
end
return ret
end
function control:Clear()
for i=1, numLines, 1 do
local LINE = name..'_LINE'..tostring(i)
if(_G[LINE]) then _G[LINE]:Clear() end
end
end
-- dirty but butt
function control:CopyAllTextToClipboard()
if(self.text) then
if(not _G["EDITBUFFER_CLIPBOARD"]) then
WINDOW_MANAGER:CreateTopLevelWindow("EDITBUFFER_CLIPBOARD")
--_G["EDITBUFFER_CLIPBOARD"]:SetDimensions(1,1)
--_G["EDITBUFFER_CLIPBOARD"]:SetAlpha(0)
if(not _G["EDITBUFFER_CLIPBOARD_CONTENT"]) then
WINDOW_MANAGER:CreateControlFromVirtual("EDITBUFFER_CLIPBOARD_CONTENT", _G["EDITBUFFER_CLIPBOARD"], "ZO_DefaultEditMultiLineForBackdrop")
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:SetAlpha(0)
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:SetCopyEnabled(true)
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:SetMaxInputChars(1000)
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:SetMouseEnabled(false)
end
end
-- partial copy & paste
if(string.len(self.text) > 1000) then
if(not _G["EDITBUFFER_ALERT"]) then
local ALERT = WINDOW_MANAGER:CreateTopLevelWindow("EDITBUFFER_ALERT")
ALERT:SetDimensions(400, 140)
ALERT:SetAnchor(CENTER, GuiRoot, CENTER)
ALERT:SetClampedToScreen(true)
ALERT:SetMouseEnabled(true)
ALERT:SetMovable(true)
ALERT:SetTopmost(true)
ALERT:SetHidden(false)
-- BG
WINDOW_MANAGER:CreateControlFromVirtual("EDITBUFFER_ALERT_BG", ALERT, "ZO_DefaultBackdrop")
-- CLOSE
WINDOW_MANAGER:CreateControlFromVirtual("EDITBUFFER_ALERT_CLOSE", ALERT, "ZO_CloseButton")
_G["EDITBUFFER_ALERT_CLOSE"]:SetDimensions(16, 16)
_G["EDITBUFFER_ALERT_CLOSE"]:SetAnchor(TOPRIGHT, ALERT, TOPRIGHT, 0, 0)
_G["EDITBUFFER_ALERT_CLOSE"]:SetHandler("OnMouseDown", function(self)
_G["EDITBUFFER_ALERT"]:SetHidden(true)
_G["EDITBUFFER_ALERT"]:SetTopmost(false)
end)
-- TITLE
WINDOW_MANAGER:CreateControlFromVirtual("EDITBUFFER_ALERT_TITLE", ALERT, "ZO_WindowTitle")
_G["EDITBUFFER_ALERT_TITLE"]:SetHorizontalAlignment(CENTER)
_G["EDITBUFFER_ALERT_TITLE"]:ClearAnchors()
_G["EDITBUFFER_ALERT_TITLE"]:SetAnchor(TOPLEFT, ALERT, TOPLEFT, 0, -1)
_G["EDITBUFFER_ALERT_TITLE"]:SetAnchor(TOPRIGHT, ALERT, TOPRIGHT, 0, -1)
_G["EDITBUFFER_ALERT_TITLE"]:SetText("PARTIAL COPY AND PASTE!")
-- DIVIDER
WINDOW_MANAGER:CreateControl("EDITBUFFER_ALERT_DIVIDER", ALERT, CT_TEXTURE)
_G["EDITBUFFER_ALERT_DIVIDER"]:SetTexture("EsoUI/Art/Miscellaneous/horizontalDivider.dds")
_G["EDITBUFFER_ALERT_DIVIDER"]:SetDimensions(nil, 4)
_G["EDITBUFFER_ALERT_DIVIDER"]:SetAnchor(TOPLEFT, ALERT, TOPLEFT, -80, 40)
_G["EDITBUFFER_ALERT_DIVIDER"]:SetAnchor(TOPRIGHT, ALERT, TOPRIGHT, 80, 40)
-- TEXT
WINDOW_MANAGER:CreateControl("EDITBUFFER_ALERT_TEXT", ALERT, CT_LABEL)
_G["EDITBUFFER_ALERT_TEXT"]:SetFont("ZoFontGame")
_G["EDITBUFFER_ALERT_TEXT"]:SetAnchor(CENTER, ALERT, CENTER)
_G["EDITBUFFER_ALERT_TEXT"]:SetColor(207/255, 220/255, 189/255, 1)
-- NEXT
WINDOW_MANAGER:CreateControlFromVirtual("EDITBUFFER_ALERT_NEXT", ALERT, "ZO_DefaultButton")
_G["EDITBUFFER_ALERT_NEXT"]:SetAnchor(BOTTOMLEFT, ALERT, BOTTOMLEFT, 0, -10)
_G["EDITBUFFER_ALERT_NEXT"]:SetText("NEXT")
_G["EDITBUFFER_ALERT_NEXT"]:SetHandler("OnMouseDown", function(self)
CALLBACK_MANAGER:FireCallbacks("OnClipBoardCopyNext", self)
end)
-- CANCLE
WINDOW_MANAGER:CreateControlFromVirtual("EDITBUFFER_ALERT_CANCEL", ALERT, "ZO_DefaultButton")
_G["EDITBUFFER_ALERT_CANCEL"]:SetAnchor(BOTTOMRIGHT, ALERT, BOTTOMRIGHT, 0, -10)
_G["EDITBUFFER_ALERT_CANCEL"]:SetText("CANCEL")
_G["EDITBUFFER_ALERT_CANCEL"]:SetHandler("OnMouseDown", function(self)
_G["EDITBUFFER_ALERT"]:SetHidden(true)
_G["EDITBUFFER_ALERT"]:SetTopmost(false)
end)
end
local dumped_text = self.text
local dumped_parts = self:SplitLongLines(dumped_text, 1000)
_G["EDITBUFFER_ALERT"]:SetHidden(false)
_G["EDITBUFFER_ALERT"]:SetTopmost(true)
local i = 1
local num_max = #dumped_parts
local function OnClipBoardCopyNext()
if(i > num_max) then
i = 1
_G["EDITBUFFER_ALERT"]:SetHidden(true)
_G["EDITBUFFER_ALERT"]:SetTopmost(false)
end
if(dumped_parts[i]) then
_G["EDITBUFFER_ALERT_TEXT"]:SetText('Text copied to clipboard ('..tostring(i)..' of '..tostring(num_max)..') ...')
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:Clear()
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:SetText(dumped_parts[i])
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:CopyAllTextToClipboard()
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:Clear()
end
i = i + 1
end
CALLBACK_MANAGER:RegisterCallback("OnClipBoardCopyNext", OnClipBoardCopyNext)
OnClipBoardCopyNext()
-- less or equal to 1000 chars only a single copy is needed
else
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:Clear()
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:SetText(self.text)
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:CopyAllTextToClipboard()
_G["EDITBUFFER_CLIPBOARD_CONTENT"]:Clear()
end
end
end
-- OnMouseWheel-Event
parent:SetHandler("OnMouseWheel", function(self, delta, ctrl, alt, shift, command)
-- up
if(delta > 0) then
control:ScrollUp()
-- down
elseif(delta < 0) then
control:ScrollDown()
end
end)
_G[name] = control
return _G[name]
end