farmbuyer@1
|
1 local Type, Version = "EditBoxDropDown", 3
|
farmbuyer@1
|
2 local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
farmbuyer@1
|
3 if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
farmbuyer@1
|
4
|
farmbuyer@1
|
5 --[[
|
farmbuyer@1
|
6 This is a from-scratch AceGUI-style implementation of the combination drop-
|
farmbuyer@1
|
7 down editboxes seen in DoTimer's option menus. Typing in the editbox adds
|
farmbuyer@1
|
8 entries to a list; clicking the scrolldown button displays the list in a
|
farmbuyer@1
|
9 dropdown; clicking on an entry in the dropdown removes it from the list.
|
farmbuyer@1
|
10
|
farmbuyer@1
|
11 (This type of widget may actually have a more formal name already. I first
|
farmbuyer@1
|
12 encountered it in DoTimer, so that's what I named it after.)
|
farmbuyer@1
|
13
|
farmbuyer@1
|
14 The implementation does not borrow any of DoTimer's actual code. I've tried
|
farmbuyer@1
|
15 writing this to imitate the look-and-feel of an interface that many players
|
farmbuyer@1
|
16 will find familiar and easy to use.
|
farmbuyer@1
|
17
|
farmbuyer@1
|
18 Version 2 is a rehash to follow the same form of the rest of the AceGUI widgets
|
farmbuyer@1
|
19 after their rewrite, and to work with the new EditBox behavior.
|
farmbuyer@1
|
20
|
farmbuyer@1
|
21 Version 3 adds the EditBoxDropDownOptionControl variant, specifically for use
|
farmbuyer@1
|
22 as a 'dialogControl' in AceConfig option tables. Details follow; the more
|
farmbuyer@1
|
23 disappointing restrictions are because AceConfig never gives the end user any
|
farmbuyer@1
|
24 direct link to the widgets in use.
|
farmbuyer@1
|
25 - 'desc' option field ignored
|
farmbuyer@1
|
26 - 'name' field may contain an embedded tab ('\t') followed by more text to be
|
farmbuyer@1
|
27 used as the tooltip text when hovering over the editbox field
|
farmbuyer@1
|
28 - 'get' field must be a function, returning a function to be used as the
|
farmbuyer@1
|
29 OnTextEnterPressed callback; this is typically how new entries should be
|
farmbuyer@1
|
30 added to data
|
farmbuyer@1
|
31 - 'values' field must be a function, returning the usual list of entries, PLUS
|
farmbuyer@1
|
32 the callback used for 'get', e.g.,
|
farmbuyer@1
|
33 values = function()
|
farmbuyer@1
|
34 local ret = build_real_dropdown_values()
|
farmbuyer@1
|
35 ret[get_callback] = true -- assuming "function get_callback (widget, event, text)"
|
farmbuyer@1
|
36 return ret
|
farmbuyer@1
|
37 end
|
farmbuyer@1
|
38 The callback will be immediately removed from the table, but is required to
|
farmbuyer@1
|
39 be present to pass tests in the AceConfig source.
|
farmbuyer@1
|
40 - 'set' receives the key of the dropdown table, but that entry will already be
|
farmbuyer@1
|
41 removed by the time the 'set' function is called
|
farmbuyer@1
|
42
|
farmbuyer@1
|
43
|
farmbuyer@1
|
44 EditBoxDropDown API
|
farmbuyer@1
|
45
|
farmbuyer@1
|
46 :SetLabel(txt)
|
farmbuyer@1
|
47 forwards to the editbox's SetLabel
|
farmbuyer@1
|
48
|
farmbuyer@1
|
49 :SetText(txt)
|
farmbuyer@1
|
50 forwards to the editbox's SetText
|
farmbuyer@1
|
51
|
farmbuyer@1
|
52 :SetEditBoxTooltip(txt)
|
farmbuyer@1
|
53 sets text for the tooltip shown when hovering over the editbox
|
farmbuyer@1
|
54 no default
|
farmbuyer@1
|
55
|
farmbuyer@1
|
56 :SetButtonTooltip(txt)
|
farmbuyer@1
|
57 sets text for the tooltip shown when hovering over the dropdown button
|
farmbuyer@1
|
58 default "Click on entries to remove them."
|
farmbuyer@1
|
59
|
farmbuyer@1
|
60 :SetList(t)
|
farmbuyer@1
|
61 T is a table to be shown in the dropdown list; the values will be displayed
|
farmbuyer@1
|
62 in the dropdown
|
farmbuyer@1
|
63 When entries are clicked, they will be removed from T. T is not copied,
|
farmbuyer@1
|
64 the table is edited "live" before firing the callback below.
|
farmbuyer@1
|
65
|
farmbuyer@1
|
66
|
farmbuyer@1
|
67 EditBoxDropDown Callbacks
|
farmbuyer@1
|
68
|
farmbuyer@1
|
69 OnTextEnterPressed
|
farmbuyer@1
|
70 same as the editbox's OnEnterPressed
|
farmbuyer@1
|
71
|
farmbuyer@1
|
72 OnListItemClicked
|
farmbuyer@1
|
73 similar to a Dropdown widget's OnValueChanged, the key and value from the
|
farmbuyer@1
|
74 table given to :SetList are passed
|
farmbuyer@1
|
75
|
farmbuyer@1
|
76
|
farmbuyer@1
|
77 farmbuyer
|
farmbuyer@1
|
78 ]]
|
farmbuyer@1
|
79
|
farmbuyer@1
|
80 local button_hover_text_default = "Click on entries to remove them."
|
farmbuyer@1
|
81 local maps -- from actual editbox frame back to this widget
|
farmbuyer@1
|
82
|
farmbuyer@1
|
83
|
farmbuyer@1
|
84 local function Menu_OnClick (button, userlist_key, widget)
|
farmbuyer@1
|
85 local v = widget.list[userlist_key]
|
farmbuyer@1
|
86 widget.list[userlist_key] = nil
|
farmbuyer@1
|
87 widget.dropdown.is_on = nil
|
farmbuyer@1
|
88 -- firing these off changes widget contents, must be done last :-(
|
farmbuyer@1
|
89 widget:Fire("OnListItemClicked", userlist_key, v)
|
farmbuyer@1
|
90 widget:Fire("OnValueChanged", userlist_key)
|
farmbuyer@1
|
91 end
|
farmbuyer@1
|
92
|
farmbuyer@1
|
93 local function BuildList (widget)
|
farmbuyer@1
|
94 local ret = {}
|
farmbuyer@1
|
95 if widget.list then for k,v in pairs(widget.list) do
|
farmbuyer@1
|
96 table.insert (ret, {
|
farmbuyer@1
|
97 text = tostring(v) or tostring(k),
|
farmbuyer@1
|
98 func = Menu_OnClick,
|
farmbuyer@1
|
99 arg1 = k,
|
farmbuyer@1
|
100 arg2 = widget,
|
farmbuyer@1
|
101 notCheckable = true,
|
farmbuyer@1
|
102 })
|
farmbuyer@1
|
103 end end
|
farmbuyer@1
|
104 return ret
|
farmbuyer@1
|
105 end
|
farmbuyer@1
|
106
|
farmbuyer@1
|
107
|
farmbuyer@1
|
108 local function ddEditBox_OnMouseEnter (editbox)
|
farmbuyer@1
|
109 if editbox.tooltip_text then
|
farmbuyer@1
|
110 GameTooltip:SetOwner(editbox.frame, "ANCHOR_RIGHT")
|
farmbuyer@1
|
111 GameTooltip:SetText(editbox.tooltip_text, nil, nil, nil, nil, 1)
|
farmbuyer@1
|
112 end
|
farmbuyer@1
|
113 end
|
farmbuyer@1
|
114
|
farmbuyer@1
|
115 local function ddEditBox_OnMouseLeave (editbox_or_button)
|
farmbuyer@1
|
116 GameTooltip:Hide()
|
farmbuyer@1
|
117 end
|
farmbuyer@1
|
118
|
farmbuyer@1
|
119 local function ddEditBox_Clear (editboxframe)
|
farmbuyer@1
|
120 editboxframe:SetText("")
|
farmbuyer@1
|
121 end
|
farmbuyer@1
|
122
|
farmbuyer@1
|
123 local function ddEditBox_Reset (editboxframe) -- :ClearFocus triggers this
|
farmbuyer@1
|
124 editboxframe:SetText(maps[editboxframe].editbox_basetext or "")
|
farmbuyer@1
|
125 end
|
farmbuyer@1
|
126
|
farmbuyer@1
|
127 local function ddEditBox_OnEnterPressed (editbox, _, text)
|
farmbuyer@1
|
128 editbox.obj:Fire("OnTextEnterPressed", text)
|
farmbuyer@1
|
129 ddEditBox_Reset(editbox.editbox)
|
farmbuyer@1
|
130 editbox.editbox:ClearFocus() -- cursor still blinking in there, one more time
|
farmbuyer@1
|
131 end
|
farmbuyer@1
|
132
|
farmbuyer@1
|
133 local function Button_OnClick (button)
|
farmbuyer@1
|
134 local dd = button.obj.dropdown
|
farmbuyer@1
|
135 -- Annoyingly, it's very tedious to find the correct nested frame to use
|
farmbuyer@1
|
136 -- for :IsShown() here. We'll avoid it all by using our own flag.
|
farmbuyer@1
|
137 if dd.is_on then
|
farmbuyer@1
|
138 dd.is_on = nil
|
farmbuyer@1
|
139 HideDropDownMenu(--[[level=]]1) -- EasyMenu always uses top/1 level
|
farmbuyer@1
|
140 else
|
farmbuyer@1
|
141 dd.is_on = true
|
farmbuyer@1
|
142 local t = BuildList(button.obj)
|
farmbuyer@1
|
143 EasyMenu (t, button.obj.dropdown, button.obj.frame, 0, 0, "MENU")
|
farmbuyer@1
|
144 PlaySound("igMainMenuOptionCheckBoxOn")
|
farmbuyer@1
|
145 end
|
farmbuyer@1
|
146 end
|
farmbuyer@1
|
147
|
farmbuyer@1
|
148 local function Button_OnEnter (button)
|
farmbuyer@1
|
149 if button.tooltip_text then
|
farmbuyer@1
|
150 GameTooltip:SetOwner(button, "ANCHOR_RIGHT")
|
farmbuyer@1
|
151 GameTooltip:SetText(button.tooltip_text, nil, nil, nil, nil, 1)
|
farmbuyer@1
|
152 end
|
farmbuyer@1
|
153 end
|
farmbuyer@1
|
154
|
farmbuyer@1
|
155
|
farmbuyer@1
|
156 local methods = {
|
farmbuyer@1
|
157 ["OnAcquire"] = function (self)
|
farmbuyer@1
|
158 self:SetHeight(20)
|
farmbuyer@1
|
159 self:SetWidth(100)
|
farmbuyer@1
|
160 self.button.tooltip_text = button_hover_text_default
|
farmbuyer@1
|
161 self:SetList(nil)
|
farmbuyer@1
|
162 self.editbox:DisableButton(true)
|
farmbuyer@1
|
163
|
farmbuyer@1
|
164 maps = maps or {}
|
farmbuyer@1
|
165 maps[self.editbox.editbox] = self
|
farmbuyer@1
|
166 end,
|
farmbuyer@1
|
167
|
farmbuyer@1
|
168 ["OnRelease"] = function (self)
|
farmbuyer@1
|
169 self.frame:ClearAllPoints()
|
farmbuyer@1
|
170 self.frame:Hide()
|
farmbuyer@1
|
171 self.editbox.tooltip_text = nil
|
farmbuyer@1
|
172 self.button.tooltip_text = nil
|
farmbuyer@1
|
173 self:SetList(nil)
|
farmbuyer@1
|
174 maps[self.editbox.editbox] = nil
|
farmbuyer@1
|
175 end,
|
farmbuyer@1
|
176
|
farmbuyer@1
|
177 ["SetParent"] = function (self, parent)
|
farmbuyer@1
|
178 self.frame:SetParent(nil)
|
farmbuyer@1
|
179 self.frame:SetParent(parent.content)
|
farmbuyer@1
|
180 self.parent = parent
|
farmbuyer@1
|
181 self.editbox:SetParent(parent)
|
farmbuyer@1
|
182 end,
|
farmbuyer@1
|
183
|
farmbuyer@1
|
184 ["SetText"] = function (self, text)
|
farmbuyer@1
|
185 self.editbox_basetext = text
|
farmbuyer@1
|
186 return self.editbox:SetText(text)
|
farmbuyer@1
|
187 end,
|
farmbuyer@1
|
188
|
farmbuyer@1
|
189 ["SetLabel"] = function (self, text)
|
farmbuyer@1
|
190 return self.editbox:SetLabel(text)
|
farmbuyer@1
|
191 end,
|
farmbuyer@1
|
192
|
farmbuyer@1
|
193 ["SetDisabled"] = function (self, disabled)
|
farmbuyer@1
|
194 self.editbox:SetDisabled(disabled)
|
farmbuyer@1
|
195 if disabled then
|
farmbuyer@1
|
196 self.button:Disable()
|
farmbuyer@1
|
197 else
|
farmbuyer@1
|
198 self.button:Enable()
|
farmbuyer@1
|
199 end
|
farmbuyer@1
|
200 end,
|
farmbuyer@1
|
201
|
farmbuyer@1
|
202 ["SetList"] = function (self, list)
|
farmbuyer@1
|
203 self.list = list
|
farmbuyer@1
|
204 end,
|
farmbuyer@1
|
205
|
farmbuyer@1
|
206 ["SetEditBoxTooltip"] = function (self, text)
|
farmbuyer@1
|
207 self.editbox.tooltip_text = text
|
farmbuyer@1
|
208 end,
|
farmbuyer@1
|
209
|
farmbuyer@1
|
210 ["SetButtonTooltip"] = function (self, text)
|
farmbuyer@1
|
211 self.button.tooltip_text = text
|
farmbuyer@1
|
212 end,
|
farmbuyer@1
|
213 }
|
farmbuyer@1
|
214
|
farmbuyer@1
|
215 -- called with the 'name' entry
|
farmbuyer@1
|
216 local function optcontrol_SetLabel (self, text)
|
farmbuyer@1
|
217 local name, desc = ('\t'):split(text)
|
farmbuyer@1
|
218 if desc then
|
farmbuyer@1
|
219 self:SetEditBoxTooltip(desc)
|
farmbuyer@1
|
220 end
|
farmbuyer@1
|
221 self.editbox:SetLabel(name)
|
farmbuyer@1
|
222 end
|
farmbuyer@1
|
223
|
farmbuyer@1
|
224 local function optcontrol_SetValue (self, epcallback)
|
farmbuyer@1
|
225 -- set the callback
|
farmbuyer@1
|
226 self:SetCallback("OnTextEnterPressed", epcallback)
|
farmbuyer@1
|
227 -- remove the fake entry from the values table
|
farmbuyer@1
|
228 self.list[epcallback] = nil
|
farmbuyer@1
|
229 end
|
farmbuyer@1
|
230
|
farmbuyer@1
|
231
|
farmbuyer@1
|
232 local function Constructor(is_option_control)
|
farmbuyer@1
|
233 local num = AceGUI:GetNextWidgetNum(Type)
|
farmbuyer@1
|
234
|
farmbuyer@1
|
235 -- Its frame becomes our widget frame, else its frame is never shown. Gluing
|
farmbuyer@1
|
236 -- them together seems a little evil, but it beats making this widget into a
|
farmbuyer@1
|
237 -- formal containter. Inspired by new-style InteractiveLabel.
|
farmbuyer@1
|
238 local editbox = AceGUI:Create("EditBox")
|
farmbuyer@1
|
239 local frame = editbox.frame
|
farmbuyer@1
|
240 editbox:SetHeight(20)
|
farmbuyer@1
|
241 editbox:SetWidth(100)
|
farmbuyer@1
|
242 frame:SetWidth(frame:GetWidth()+6)
|
farmbuyer@1
|
243 editbox:SetCallback("OnEnter", ddEditBox_OnMouseEnter)
|
farmbuyer@1
|
244 editbox:SetCallback("OnLeave", ddEditBox_OnMouseLeave)
|
farmbuyer@1
|
245 editbox:SetCallback("OnEnterPressed", ddEditBox_OnEnterPressed)
|
farmbuyer@1
|
246 editbox.editbox:SetScript("OnEditFocusGained", ddEditBox_Clear)
|
farmbuyer@1
|
247 editbox.editbox:SetScript("OnEditFocusLost", ddEditBox_Reset)
|
farmbuyer@1
|
248 --editbox.editbox:SetScript("OnEscapePressed", ddEditBox_Reset)
|
farmbuyer@1
|
249
|
farmbuyer@1
|
250 local button = CreateFrame("Button", nil, frame)
|
farmbuyer@1
|
251 button:SetHeight(20)
|
farmbuyer@1
|
252 button:SetWidth(24)
|
farmbuyer@1
|
253 button:SetPoint("LEFT", editbox.frame, "RIGHT", 0, 0)
|
farmbuyer@1
|
254 button:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up")
|
farmbuyer@1
|
255 button:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down")
|
farmbuyer@1
|
256 button:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled")
|
farmbuyer@1
|
257 button:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight","ADD")
|
farmbuyer@1
|
258 button:SetScript("OnClick", Button_OnClick)
|
farmbuyer@1
|
259 button:SetScript("OnEnter", Button_OnEnter)
|
farmbuyer@1
|
260 button:SetScript("OnLeave", ddEditBox_OnMouseLeave)
|
farmbuyer@1
|
261 button.parent = frame
|
farmbuyer@1
|
262
|
farmbuyer@1
|
263 local dropdown = CreateFrame("Frame", "AceGUI-3.0EditBoxDropDownMenu"..num, nil, "UIDropDownMenuTemplate")
|
farmbuyer@1
|
264 dropdown:Hide()
|
farmbuyer@1
|
265
|
farmbuyer@1
|
266 local widget = {
|
farmbuyer@1
|
267 editbox = editbox,
|
farmbuyer@1
|
268 button = button,
|
farmbuyer@1
|
269 dropdown = dropdown,
|
farmbuyer@1
|
270 frame = frame,
|
farmbuyer@1
|
271 type = Type
|
farmbuyer@1
|
272 }
|
farmbuyer@1
|
273 for method, func in pairs(methods) do
|
farmbuyer@1
|
274 widget[method] = func
|
farmbuyer@1
|
275 end
|
farmbuyer@1
|
276 editbox.obj, button.obj, dropdown.obj = widget, widget, widget
|
farmbuyer@1
|
277 if is_option_control then
|
farmbuyer@1
|
278 widget.is_option_control = true
|
farmbuyer@1
|
279 widget.SetLabel = optcontrol_SetLabel
|
farmbuyer@1
|
280 widget.SetValue = optcontrol_SetValue
|
farmbuyer@1
|
281 end
|
farmbuyer@1
|
282
|
farmbuyer@1
|
283 return AceGUI:RegisterAsWidget(widget)
|
farmbuyer@1
|
284 end
|
farmbuyer@1
|
285
|
farmbuyer@1
|
286 AceGUI:RegisterWidgetType (Type, Constructor, Version)
|
farmbuyer@1
|
287
|
farmbuyer@1
|
288 AceGUI:RegisterWidgetType (Type.."OptionControl", function() return Constructor(true) end, Version)
|
farmbuyer@1
|
289
|