comparison AceGUIWidget-DoTimerEditBoxDropDown.lua @ 1:822b6ca3ef89

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