1553757 - Refactor updateIndicators
[wowui.git] / libs / AceGUI-3.0-SharedMediaWidgets / Libs / AceGUI-3.0 / widgets / AceGUIWidget-MultiLineEditBox.lua
1 local Type, Version = "MultiLineEditBox", 27
2 local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
3 if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
4
5 -- Lua APIs
6 local pairs = pairs
7
8 -- WoW APIs
9 local GetCursorInfo, GetSpellInfo, ClearCursor = GetCursorInfo, GetSpellInfo, ClearCursor
10 local CreateFrame, UIParent = CreateFrame, UIParent
11 local _G = _G
12
13 -- Global vars/functions that we don't upvalue since they might get hooked, or upgraded
14 -- List them here for Mikk's FindGlobals script
15 -- GLOBALS: ACCEPT, ChatFontNormal
16
17 local wowMoP
18 do
19         local _, _, _, interface = GetBuildInfo()
20         wowMoP = (interface >= 50000)
21 end
22
23 --[[-----------------------------------------------------------------------------
24 Support functions
25 -------------------------------------------------------------------------------]]
26
27 if not AceGUIMultiLineEditBoxInsertLink then
28         -- upgradeable hook
29         hooksecurefunc("ChatEdit_InsertLink", function(...) return _G.AceGUIMultiLineEditBoxInsertLink(...) end)
30 end
31
32 function _G.AceGUIMultiLineEditBoxInsertLink(text)
33         for i = 1, AceGUI:GetWidgetCount(Type) do
34                 local editbox = _G[("MultiLineEditBox%uEdit"):format(i)]
35                 if editbox and editbox:IsVisible() and editbox:HasFocus() then
36                         editbox:Insert(text)
37                         return true
38                 end
39         end
40 end
41
42
43 local function Layout(self)
44         self:SetHeight(self.numlines * 14 + (self.disablebutton and 19 or 41) + self.labelHeight)
45
46         if self.labelHeight == 0 then
47                 self.scrollBar:SetPoint("TOP", self.frame, "TOP", 0, -23)
48         else
49                 self.scrollBar:SetPoint("TOP", self.label, "BOTTOM", 0, -19)
50         end
51
52         if self.disablebutton then
53                 self.scrollBar:SetPoint("BOTTOM", self.frame, "BOTTOM", 0, 21)
54                 self.scrollBG:SetPoint("BOTTOMLEFT", 0, 4)
55         else
56                 self.scrollBar:SetPoint("BOTTOM", self.button, "TOP", 0, 18)
57                 self.scrollBG:SetPoint("BOTTOMLEFT", self.button, "TOPLEFT")
58         end
59 end
60
61 --[[-----------------------------------------------------------------------------
62 Scripts
63 -------------------------------------------------------------------------------]]
64 local function OnClick(self)                                                     -- Button
65         self = self.obj
66         self.editBox:ClearFocus()
67         if not self:Fire("OnEnterPressed", self.editBox:GetText()) then
68                 self.button:Disable()
69         end
70 end
71
72 local function OnCursorChanged(self, _, y, _, cursorHeight)                      -- EditBox
73         self, y = self.obj.scrollFrame, -y
74         local offset = self:GetVerticalScroll()
75         if y < offset then
76                 self:SetVerticalScroll(y)
77         else
78                 y = y + cursorHeight - self:GetHeight()
79                 if y > offset then
80                         self:SetVerticalScroll(y)
81                 end
82         end
83 end
84
85 local function OnEditFocusLost(self)                                             -- EditBox
86         self:HighlightText(0, 0)
87         self.obj:Fire("OnEditFocusLost")
88 end
89
90 local function OnEnter(self)                                                     -- EditBox / ScrollFrame
91         self = self.obj
92         if not self.entered then
93                 self.entered = true
94                 self:Fire("OnEnter")
95         end
96 end
97
98 local function OnLeave(self)                                                     -- EditBox / ScrollFrame
99         self = self.obj
100         if self.entered then
101                 self.entered = nil
102                 self:Fire("OnLeave")
103         end
104 end
105
106 local function OnMouseUp(self)                                                   -- ScrollFrame
107         self = self.obj.editBox
108         self:SetFocus()
109         self:SetCursorPosition(self:GetNumLetters())
110 end
111
112 local function OnReceiveDrag(self)                                               -- EditBox / ScrollFrame
113         local type, id, info = GetCursorInfo()
114         if type == "spell" then
115                 info = GetSpellInfo(id, info)
116         elseif type ~= "item" then
117                 return
118         end
119         ClearCursor()
120         self = self.obj
121         local editBox = self.editBox
122         if not editBox:HasFocus() then
123                 editBox:SetFocus()
124                 editBox:SetCursorPosition(editBox:GetNumLetters())
125         end
126         editBox:Insert(info)
127         self.button:Enable()
128 end
129
130 local function OnSizeChanged(self, width, height)                                -- ScrollFrame
131         self.obj.editBox:SetWidth(width)
132 end
133
134 local function OnTextChanged(self, userInput)                                    -- EditBox
135         if userInput then
136                 self = self.obj
137                 self:Fire("OnTextChanged", self.editBox:GetText())
138                 self.button:Enable()
139         end
140 end
141
142 local function OnTextSet(self)                                                   -- EditBox
143         self:HighlightText(0, 0)
144         self:SetCursorPosition(self:GetNumLetters())
145         self:SetCursorPosition(0)
146         self.obj.button:Disable()
147 end
148
149 local function OnVerticalScroll(self, offset)                                    -- ScrollFrame
150         local editBox = self.obj.editBox
151         editBox:SetHitRectInsets(0, 0, offset, editBox:GetHeight() - offset - self:GetHeight())
152 end
153
154 local function OnShowFocus(frame)
155         frame.obj.editBox:SetFocus()
156         frame:SetScript("OnShow", nil)
157 end
158
159 local function OnEditFocusGained(frame)
160         AceGUI:SetFocus(frame.obj)
161         frame.obj:Fire("OnEditFocusGained")
162 end
163
164 --[[-----------------------------------------------------------------------------
165 Methods
166 -------------------------------------------------------------------------------]]
167 local methods = {
168         ["OnAcquire"] = function(self)
169                 self.editBox:SetText("")
170                 self:SetDisabled(false)
171                 self:SetWidth(200)
172                 self:DisableButton(false)
173                 self:SetNumLines()
174                 self.entered = nil
175                 self:SetMaxLetters(0)
176         end,
177
178         ["OnRelease"] = function(self)
179                 self:ClearFocus()
180         end,
181
182         ["SetDisabled"] = function(self, disabled)
183                 local editBox = self.editBox
184                 if disabled then
185                         editBox:ClearFocus()
186                         editBox:EnableMouse(false)
187                         editBox:SetTextColor(0.5, 0.5, 0.5)
188                         self.label:SetTextColor(0.5, 0.5, 0.5)
189                         self.scrollFrame:EnableMouse(false)
190                         self.button:Disable()
191                 else
192                         editBox:EnableMouse(true)
193                         editBox:SetTextColor(1, 1, 1)
194                         self.label:SetTextColor(1, 0.82, 0)
195                         self.scrollFrame:EnableMouse(true)
196                 end
197         end,
198
199         ["SetLabel"] = function(self, text)
200                 if text and text ~= "" then
201                         self.label:SetText(text)
202                         if self.labelHeight ~= 10 then
203                                 self.labelHeight = 10
204                                 self.label:Show()
205                         end
206                 elseif self.labelHeight ~= 0 then
207                         self.labelHeight = 0
208                         self.label:Hide()
209                 end
210                 Layout(self)
211         end,
212
213         ["SetNumLines"] = function(self, value)
214                 if not value or value < 4 then
215                         value = 4
216                 end
217                 self.numlines = value
218                 Layout(self)
219         end,
220
221         ["SetText"] = function(self, text)
222                 self.editBox:SetText(text)
223         end,
224
225         ["GetText"] = function(self)
226                 return self.editBox:GetText()
227         end,
228
229         ["SetMaxLetters"] = function (self, num)
230                 self.editBox:SetMaxLetters(num or 0)
231         end,
232
233         ["DisableButton"] = function(self, disabled)
234                 self.disablebutton = disabled
235                 if disabled then
236                         self.button:Hide()
237                 else
238                         self.button:Show()
239                 end
240                 Layout(self)
241         end,
242         
243         ["ClearFocus"] = function(self)
244                 self.editBox:ClearFocus()
245                 self.frame:SetScript("OnShow", nil)
246         end,
247
248         ["SetFocus"] = function(self)
249                 self.editBox:SetFocus()
250                 if not self.frame:IsShown() then
251                         self.frame:SetScript("OnShow", OnShowFocus)
252                 end
253         end,
254         
255         ["GetCursorPosition"] = function(self)
256                 return self.editBox:GetCursorPosition()
257         end,
258         
259         ["SetCursorPosition"] = function(self, ...)
260                 return self.editBox:SetCursorPosition(...)
261         end,
262         
263         
264 }
265
266 --[[-----------------------------------------------------------------------------
267 Constructor
268 -------------------------------------------------------------------------------]]
269 local backdrop = {
270         bgFile = [[Interface\Tooltips\UI-Tooltip-Background]],
271         edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]], edgeSize = 16,
272         insets = { left = 4, right = 3, top = 4, bottom = 3 }
273 }
274
275 local function Constructor()
276         local frame = CreateFrame("Frame", nil, UIParent)
277         frame:Hide()
278         
279         local widgetNum = AceGUI:GetNextWidgetNum(Type)
280
281         local label = frame:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
282         label:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, -4)
283         label:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, -4)
284         label:SetJustifyH("LEFT")
285         label:SetText(ACCEPT)
286         label:SetHeight(10)
287
288         local button = CreateFrame("Button", ("%s%dButton"):format(Type, widgetNum), frame, wowMoP and "UIPanelButtonTemplate" or "UIPanelButtonTemplate2")
289         button:SetPoint("BOTTOMLEFT", 0, 4)
290         button:SetHeight(22)
291         button:SetWidth(label:GetStringWidth() + 24)
292         button:SetText(ACCEPT)
293         button:SetScript("OnClick", OnClick)
294         button:Disable()
295         
296         local text = button:GetFontString()
297         text:ClearAllPoints()
298         text:SetPoint("TOPLEFT", button, "TOPLEFT", 5, -5)
299         text:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -5, 1)
300         text:SetJustifyV("MIDDLE")
301
302         local scrollBG = CreateFrame("Frame", nil, frame)
303         scrollBG:SetBackdrop(backdrop)
304         scrollBG:SetBackdropColor(0, 0, 0)
305         scrollBG:SetBackdropBorderColor(0.4, 0.4, 0.4)
306
307         local scrollFrame = CreateFrame("ScrollFrame", ("%s%dScrollFrame"):format(Type, widgetNum), frame, "UIPanelScrollFrameTemplate")
308
309         local scrollBar = _G[scrollFrame:GetName() .. "ScrollBar"]
310         scrollBar:ClearAllPoints()
311         scrollBar:SetPoint("TOP", label, "BOTTOM", 0, -19)
312         scrollBar:SetPoint("BOTTOM", button, "TOP", 0, 18)
313         scrollBar:SetPoint("RIGHT", frame, "RIGHT")
314
315         scrollBG:SetPoint("TOPRIGHT", scrollBar, "TOPLEFT", 0, 19)
316         scrollBG:SetPoint("BOTTOMLEFT", button, "TOPLEFT")
317
318         scrollFrame:SetPoint("TOPLEFT", scrollBG, "TOPLEFT", 5, -6)
319         scrollFrame:SetPoint("BOTTOMRIGHT", scrollBG, "BOTTOMRIGHT", -4, 4)
320         scrollFrame:SetScript("OnEnter", OnEnter)
321         scrollFrame:SetScript("OnLeave", OnLeave)
322         scrollFrame:SetScript("OnMouseUp", OnMouseUp)
323         scrollFrame:SetScript("OnReceiveDrag", OnReceiveDrag)
324         scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
325         scrollFrame:HookScript("OnVerticalScroll", OnVerticalScroll)
326
327         local editBox = CreateFrame("EditBox", ("%s%dEdit"):format(Type, widgetNum), scrollFrame)
328         editBox:SetAllPoints()
329         editBox:SetFontObject(ChatFontNormal)
330         editBox:SetMultiLine(true)
331         editBox:EnableMouse(true)
332         editBox:SetAutoFocus(false)
333         editBox:SetCountInvisibleLetters(false)
334         editBox:SetScript("OnCursorChanged", OnCursorChanged)
335         editBox:SetScript("OnEditFocusLost", OnEditFocusLost)
336         editBox:SetScript("OnEnter", OnEnter)
337         editBox:SetScript("OnEscapePressed", editBox.ClearFocus)
338         editBox:SetScript("OnLeave", OnLeave)
339         editBox:SetScript("OnMouseDown", OnReceiveDrag)
340         editBox:SetScript("OnReceiveDrag", OnReceiveDrag)
341         editBox:SetScript("OnTextChanged", OnTextChanged)
342         editBox:SetScript("OnTextSet", OnTextSet)
343         editBox:SetScript("OnEditFocusGained", OnEditFocusGained)
344         
345
346         scrollFrame:SetScrollChild(editBox)
347
348         local widget = {
349                 button      = button,
350                 editBox     = editBox,
351                 frame       = frame,
352                 label       = label,
353                 labelHeight = 10,
354                 numlines    = 4,
355                 scrollBar   = scrollBar,
356                 scrollBG    = scrollBG,
357                 scrollFrame = scrollFrame,
358                 type        = Type
359         }
360         for method, func in pairs(methods) do
361                 widget[method] = func
362         end
363         button.obj, editBox.obj, scrollFrame.obj = widget, widget, widget
364
365         return AceGUI:RegisterAsWidget(widget)
366 end
367
368 AceGUI:RegisterWidgetType(Type, Constructor, Version)