AceGUIWidget-MultiLineEditBox.lua 10.5 KB
Newer Older
nevcairiel's avatar
nevcairiel committed
1
local Type, Version = "MultiLineEditBox", 29
2 3
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
4

5 6 7 8
-- Lua APIs
local pairs = pairs

-- WoW APIs
9
local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor
10 11 12 13 14 15 16
local CreateFrame, UIParent = CreateFrame, UIParent
local _G = _G

-- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
-- List them here for Mikk's FindGlobals script
-- GLOBALS: ACCEPT, ChatFontNormal

nevcairiel's avatar
nevcairiel committed
17 18 19
--[[-----------------------------------------------------------------------------
Support functions
-------------------------------------------------------------------------------]]
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36

if not AceGUIMultiLineEditBoxInsertLink then
	-- upgradeable hook
	hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end)
end

function _G.AceGUIMultiLineEditBoxInsertLink(text)
	for i = 1, AceGUI:GetWidgetCount(Type) do
		local editbox = _G[("MultiLineEditBox%uEdit"):format(i)]
		if editbox and editbox:IsVisible() and editbox:HasFocus() then
			editbox:Insert(text)
			return true
		end
	end
end


nevcairiel's avatar
nevcairiel committed
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
local function Layout(self)
	self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)

	if self.labelHeight == 0 then
		self.scrollBar:SetPoint("TOP", self.frame, "TOP", 0, -23)
	else
		self.scrollBar:SetPoint("TOP", self.label, "BOTTOM", 0, -19)
	end

	if self.disablebutton then
		self.scrollBar:SetPoint("BOTTOM", self.frame, "BOTTOM", 0, 21)
		self.scrollBG:SetPoint("BOTTOMLEFT", 0, 4)
	else
		self.scrollBar:SetPoint("BOTTOM", self.button, "TOP", 0, 18)
		self.scrollBG:SetPoint("BOTTOMLEFT", self.button, "TOPLEFT")
	end
end

55 56 57 58 59 60 61 62 63 64
--[[-----------------------------------------------------------------------------
Scripts
-------------------------------------------------------------------------------]]
local function OnClick(self)                                                     -- Button
	self = self.obj
	self.editBox:ClearFocus()
	if not self:Fire("OnEnterPressed", self.editBox:GetText()) then
		self.button:Disable()
	end
end
65

66 67 68 69 70 71 72 73 74 75 76 77
local function OnCursorChanged(self, _, y, _, cursorHeight)                      -- EditBox
	self, y = self.obj.scrollFrame, -y
	local offset = self:GetVerticalScroll()
	if y < offset then
		self:SetVerticalScroll(y)
	else
		y = y + cursorHeight - self:GetHeight()
		if y > offset then
			self:SetVerticalScroll(y)
		end
	end
end
78

79 80
local function OnEditFocusLost(self)                                             -- EditBox
	self:HighlightText(0, 0)
81
	self.obj:Fire("OnEditFocusLost")
82
end
83

84 85 86 87 88 89 90
local function OnEnter(self)                                                     -- EditBox / ScrollFrame
	self = self.obj
	if not self.entered then
		self.entered = true
		self:Fire("OnEnter")
	end
end
91

92 93 94 95 96 97 98
local function OnLeave(self)                                                     -- EditBox / ScrollFrame
	self = self.obj
	if self.entered then
		self.entered = nil
		self:Fire("OnLeave")
	end
end
99

100 101 102 103 104
local function OnMouseUp(self)                                                   -- ScrollFrame
	self = self.obj.editBox
	self:SetFocus()
	self:SetCursorPosition(self:GetNumLetters())
end
105

106 107 108
local function OnReceiveDrag(self)                                               -- EditBox / ScrollFrame
	local type, id, info = GetCursorInfo()
	if type == "spell" then
109
		info = GetSpellInfo(id, info)
110 111
	elseif type ~= "item" then
		return
112
	end
113 114 115 116 117 118
	ClearCursor()
	self = self.obj
	local editBox = self.editBox
	if not editBox:HasFocus() then
		editBox:SetFocus()
		editBox:SetCursorPosition(editBox:GetNumLetters())
119
	end
120 121 122 123 124 125 126 127 128 129 130 131 132
	editBox:Insert(info)
	self.button:Enable()
end

local function OnSizeChanged(self, width, height)                                -- ScrollFrame
	self.obj.editBox:SetWidth(width)
end

local function OnTextChanged(self, userInput)                                    -- EditBox
	if userInput then
		self = self.obj
		self:Fire("OnTextChanged", self.editBox:GetText())
		self.button:Enable()
133
	end
134 135 136 137 138 139 140 141 142
end

local function OnTextSet(self)                                                   -- EditBox
	self:HighlightText(0, 0)
	self:SetCursorPosition(self:GetNumLetters())
	self:SetCursorPosition(0)
	self.obj.button:Disable()
end

143
local function OnVerticalScroll(self, offset)                                    -- ScrollFrame
144 145 146 147
	local editBox = self.obj.editBox
	editBox:SetHitRectInsets(0, 0, offset, editBox:GetHeight() - offset - self:GetHeight())
end

148 149 150 151 152
local function OnShowFocus(frame)
	frame.obj.editBox:SetFocus()
	frame:SetScript("OnShow", nil)
end

153
local function OnEditFocusGained(frame)
154
	AceGUI:SetFocus(frame.obj)
155
	frame.obj:Fire("OnEditFocusGained")
156 157
end

158 159 160 161 162 163
--[[-----------------------------------------------------------------------------
Methods
-------------------------------------------------------------------------------]]
local methods = {
	["OnAcquire"] = function(self)
		self.editBox:SetText("")
164
		self:SetDisabled(false)
165
		self:SetWidth(200)
nevcairiel's avatar
nevcairiel committed
166
		self:DisableButton(false)
167 168
		self:SetNumLines()
		self.entered = nil
169
		self:SetMaxLetters(0)
170 171
	end,

172 173 174
	["OnRelease"] = function(self)
		self:ClearFocus()
	end,
175 176 177

	["SetDisabled"] = function(self, disabled)
		local editBox = self.editBox
178
		if disabled then
179 180 181 182 183
			editBox:ClearFocus()
			editBox:EnableMouse(false)
			editBox:SetTextColor(0.5, 0.5, 0.5)
			self.label:SetTextColor(0.5, 0.5, 0.5)
			self.scrollFrame:EnableMouse(false)
184
			self.button:Disable()
185
		else
186 187 188 189
			editBox:EnableMouse(true)
			editBox:SetTextColor(1, 1, 1)
			self.label:SetTextColor(1, 0.82, 0)
			self.scrollFrame:EnableMouse(true)
190
		end
191
	end,
192

193 194
	["SetLabel"] = function(self, text)
		if text and text ~= "" then
195
			self.label:SetText(text)
196 197 198 199 200 201 202
			if self.labelHeight ~= 10 then
				self.labelHeight = 10
				self.label:Show()
			end
		elseif self.labelHeight ~= 0 then
			self.labelHeight = 0
			self.label:Hide()
203
		end
nevcairiel's avatar
nevcairiel committed
204
		Layout(self)
205
	end,
206

207 208 209
	["SetNumLines"] = function(self, value)
		if not value or value < 4 then
			value = 4
210
		end
nevcairiel's avatar
nevcairiel committed
211 212
		self.numlines = value
		Layout(self)
213 214 215 216
	end,

	["SetText"] = function(self, text)
		self.editBox:SetText(text)
217 218
	end,

nevcairiel's avatar
nevcairiel committed
219 220 221 222
	["GetText"] = function(self)
		return self.editBox:GetText()
	end,

223
	["SetMaxLetters"] = function (self, num)
224
		self.editBox:SetMaxLetters(num or 0)
nevcairiel's avatar
nevcairiel committed
225 226 227 228 229 230 231 232 233 234
	end,

	["DisableButton"] = function(self, disabled)
		self.disablebutton = disabled
		if disabled then
			self.button:Hide()
		else
			self.button:Show()
		end
		Layout(self)
235
	end,
236

237 238 239 240 241 242 243 244 245 246
	["ClearFocus"] = function(self)
		self.editBox:ClearFocus()
		self.frame:SetScript("OnShow", nil)
	end,

	["SetFocus"] = function(self)
		self.editBox:SetFocus()
		if not self.frame:IsShown() then
			self.frame:SetScript("OnShow", OnShowFocus)
		end
247
	end,
248 249 250 251 252

	["HighlightText"] = function(self, from, to)
		self.editBox:HighlightText(from, to)
	end,

253 254 255
	["GetCursorPosition"] = function(self)
		return self.editBox:GetCursorPosition()
	end,
256

257 258 259
	["SetCursorPosition"] = function(self, ...)
		return self.editBox:SetCursorPosition(...)
	end,
260 261


262
}
263

264 265 266 267 268 269 270 271 272 273 274 275
--[[-----------------------------------------------------------------------------
Constructor
-------------------------------------------------------------------------------]]
local backdrop = {
	bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
	edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], edgeSize = 16,
	insets = { left = 4, right = 3, top = 4, bottom = 3 }
}

local function Constructor()
	local frame = CreateFrame("Frame", nil, UIParent)
	frame:Hide()
276

277 278 279 280 281 282 283 284 285
	local widgetNum = AceGUI:GetNextWidgetNum(Type)

	local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
	label:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -4)
	label:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -4)
	label:SetJustifyH("LEFT")
	label:SetText(ACCEPT)
	label:SetHeight(10)

286
	local button = CreateFrame("Button", ("%s%dButton"):format(Type, widgetNum), frame, "UIPanelButtonTemplate")
nevcairiel's avatar
nevcairiel committed
287
	button:SetPoint("BOTTOMLEFT", 0, 4)
288 289 290 291 292
	button:SetHeight(22)
	button:SetWidth(label:GetStringWidth() + 24)
	button:SetText(ACCEPT)
	button:SetScript("OnClick", OnClick)
	button:Disable()
293

294 295 296 297 298
	local text = button:GetFontString()
	text:ClearAllPoints()
	text:SetPoint("TOPLEFT", button, "TOPLEFT", 5, -5)
	text:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -5, 1)
	text:SetJustifyV("MIDDLE")
299

nevcairiel's avatar
nevcairiel committed
300
	local scrollBG = CreateFrame("Frame", nil, frame, BackdropTemplateMixin and "BackdropTemplate" or nil)
301 302 303 304 305 306 307 308 309 310 311 312 313 314
	scrollBG:SetBackdrop(backdrop)
	scrollBG:SetBackdropColor(0, 0, 0)
	scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)

	local scrollFrame = CreateFrame("ScrollFrame", ("%s%dScrollFrame"):format(Type, widgetNum), frame, "UIPanelScrollFrameTemplate")

	local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
	scrollBar:ClearAllPoints()
	scrollBar:SetPoint("TOP", label, "BOTTOM", 0, -19)
	scrollBar:SetPoint("BOTTOM", button, "TOP", 0, 18)
	scrollBar:SetPoint("RIGHT", frame, "RIGHT")

	scrollBG:SetPoint("TOPRIGHT", scrollBar, "TOPLEFT", 0, 19)
	scrollBG:SetPoint("BOTTOMLEFT", button, "TOPLEFT")
315

316 317 318 319 320 321 322 323
	scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 5, -6)
	scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -4, 4)
	scrollFrame:SetScript("OnEnter", OnEnter)
	scrollFrame:SetScript("OnLeave", OnLeave)
	scrollFrame:SetScript("OnMouseUp", OnMouseUp)
	scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
	scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
	scrollFrame:HookScript("OnVerticalScroll", OnVerticalScroll)
324

325
	local editBox = CreateFrame("EditBox", ("%s%dEdit"):format(Type, widgetNum), scrollFrame)
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
	editBox:SetAllPoints()
	editBox:SetFontObject(ChatFontNormal)
	editBox:SetMultiLine(true)
	editBox:EnableMouse(true)
	editBox:SetAutoFocus(false)
	editBox:SetCountInvisibleLetters(false)
	editBox:SetScript("OnCursorChanged", OnCursorChanged)
	editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
	editBox:SetScript("OnEnter", OnEnter)
	editBox:SetScript("OnEscapePressed", editBox.ClearFocus)
	editBox:SetScript("OnLeave", OnLeave)
	editBox:SetScript("OnMouseDown", OnReceiveDrag)
	editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
	editBox:SetScript("OnTextChanged", OnTextChanged)
	editBox:SetScript("OnTextSet", OnTextSet)
341
	editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
342

343 344 345 346 347 348 349 350 351

	scrollFrame:SetScrollChild(editBox)

	local widget = {
		button      = button,
		editBox     = editBox,
		frame       = frame,
		label       = label,
		labelHeight = 10,
nevcairiel's avatar
nevcairiel committed
352
		numlines    = 4,
353
		scrollBar   = scrollBar,
nevcairiel's avatar
nevcairiel committed
354
		scrollBG    = scrollBG,
355 356 357 358 359 360 361 362
		scrollFrame = scrollFrame,
		type        = Type
	}
	for method, func in pairs(methods) do
		widget[method] = func
	end
	button.obj, editBox.obj, scrollFrame.obj = widget, widget, widget

nevcairiel's avatar
nevcairiel committed
363
	return AceGUI:RegisterAsWidget(widget)
364
end
365

366
AceGUI:RegisterWidgetType(Type, Constructor, Version)