Mercurial > wow > ouroloot
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/AceGUIWidget-DoTimerEditBoxDropDown.lua Sat Apr 16 06:03:29 2011 +0000 @@ -0,0 +1,289 @@ +local Type, Version = "EditBoxDropDown", 3 +local AceGUI = LibStub and LibStub("AceGUI-3.0", true) +if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end + +--[[ +This is a from-scratch AceGUI-style implementation of the combination drop- +down editboxes seen in DoTimer's option menus. Typing in the editbox adds +entries to a list; clicking the scrolldown button displays the list in a +dropdown; clicking on an entry in the dropdown removes it from the list. + +(This type of widget may actually have a more formal name already. I first +encountered it in DoTimer, so that's what I named it after.) + +The implementation does not borrow any of DoTimer's actual code. I've tried +writing this to imitate the look-and-feel of an interface that many players +will find familiar and easy to use. + +Version 2 is a rehash to follow the same form of the rest of the AceGUI widgets +after their rewrite, and to work with the new EditBox behavior. + +Version 3 adds the EditBoxDropDownOptionControl variant, specifically for use +as a 'dialogControl' in AceConfig option tables. Details follow; the more +disappointing restrictions are because AceConfig never gives the end user any +direct link to the widgets in use. +- 'desc' option field ignored +- 'name' field may contain an embedded tab ('\t') followed by more text to be + used as the tooltip text when hovering over the editbox field +- 'get' field must be a function, returning a function to be used as the + OnTextEnterPressed callback; this is typically how new entries should be + added to data +- 'values' field must be a function, returning the usual list of entries, PLUS + the callback used for 'get', e.g., + values = function() + local ret = build_real_dropdown_values() + ret[get_callback] = true -- assuming "function get_callback (widget, event, text)" + return ret + end + The callback will be immediately removed from the table, but is required to + be present to pass tests in the AceConfig source. +- 'set' receives the key of the dropdown table, but that entry will already be + removed by the time the 'set' function is called + + +EditBoxDropDown API + +:SetLabel(txt) + forwards to the editbox's SetLabel + +:SetText(txt) + forwards to the editbox's SetText + +:SetEditBoxTooltip(txt) + sets text for the tooltip shown when hovering over the editbox + no default + +:SetButtonTooltip(txt) + sets text for the tooltip shown when hovering over the dropdown button + default "Click on entries to remove them." + +:SetList(t) + T is a table to be shown in the dropdown list; the values will be displayed + in the dropdown + When entries are clicked, they will be removed from T. T is not copied, + the table is edited "live" before firing the callback below. + + +EditBoxDropDown Callbacks + +OnTextEnterPressed + same as the editbox's OnEnterPressed + +OnListItemClicked + similar to a Dropdown widget's OnValueChanged, the key and value from the + table given to :SetList are passed + + +farmbuyer +]] + +local button_hover_text_default = "Click on entries to remove them." +local maps -- from actual editbox frame back to this widget + + +local function Menu_OnClick (button, userlist_key, widget) + local v = widget.list[userlist_key] + widget.list[userlist_key] = nil + widget.dropdown.is_on = nil + -- firing these off changes widget contents, must be done last :-( + widget:Fire("OnListItemClicked", userlist_key, v) + widget:Fire("OnValueChanged", userlist_key) +end + +local function BuildList (widget) + local ret = {} + if widget.list then for k,v in pairs(widget.list) do + table.insert (ret, { + text = tostring(v) or tostring(k), + func = Menu_OnClick, + arg1 = k, + arg2 = widget, + notCheckable = true, + }) + end end + return ret +end + + +local function ddEditBox_OnMouseEnter (editbox) + if editbox.tooltip_text then + GameTooltip:SetOwner(editbox.frame, "ANCHOR_RIGHT") + GameTooltip:SetText(editbox.tooltip_text, nil, nil, nil, nil, 1) + end +end + +local function ddEditBox_OnMouseLeave (editbox_or_button) + GameTooltip:Hide() +end + +local function ddEditBox_Clear (editboxframe) + editboxframe:SetText("") +end + +local function ddEditBox_Reset (editboxframe) -- :ClearFocus triggers this + editboxframe:SetText(maps[editboxframe].editbox_basetext or "") +end + +local function ddEditBox_OnEnterPressed (editbox, _, text) + editbox.obj:Fire("OnTextEnterPressed", text) + ddEditBox_Reset(editbox.editbox) + editbox.editbox:ClearFocus() -- cursor still blinking in there, one more time +end + +local function Button_OnClick (button) + local dd = button.obj.dropdown + -- Annoyingly, it's very tedious to find the correct nested frame to use + -- for :IsShown() here. We'll avoid it all by using our own flag. + if dd.is_on then + dd.is_on = nil + HideDropDownMenu(--[[level=]]1) -- EasyMenu always uses top/1 level + else + dd.is_on = true + local t = BuildList(button.obj) + EasyMenu (t, button.obj.dropdown, button.obj.frame, 0, 0, "MENU") + PlaySound("igMainMenuOptionCheckBoxOn") + end +end + +local function Button_OnEnter (button) + if button.tooltip_text then + GameTooltip:SetOwner(button, "ANCHOR_RIGHT") + GameTooltip:SetText(button.tooltip_text, nil, nil, nil, nil, 1) + end +end + + +local methods = { + ["OnAcquire"] = function (self) + self:SetHeight(20) + self:SetWidth(100) + self.button.tooltip_text = button_hover_text_default + self:SetList(nil) + self.editbox:DisableButton(true) + + maps = maps or {} + maps[self.editbox.editbox] = self + end, + + ["OnRelease"] = function (self) + self.frame:ClearAllPoints() + self.frame:Hide() + self.editbox.tooltip_text = nil + self.button.tooltip_text = nil + self:SetList(nil) + maps[self.editbox.editbox] = nil + end, + + ["SetParent"] = function (self, parent) + self.frame:SetParent(nil) + self.frame:SetParent(parent.content) + self.parent = parent + self.editbox:SetParent(parent) + end, + + ["SetText"] = function (self, text) + self.editbox_basetext = text + return self.editbox:SetText(text) + end, + + ["SetLabel"] = function (self, text) + return self.editbox:SetLabel(text) + end, + + ["SetDisabled"] = function (self, disabled) + self.editbox:SetDisabled(disabled) + if disabled then + self.button:Disable() + else + self.button:Enable() + end + end, + + ["SetList"] = function (self, list) + self.list = list + end, + + ["SetEditBoxTooltip"] = function (self, text) + self.editbox.tooltip_text = text + end, + + ["SetButtonTooltip"] = function (self, text) + self.button.tooltip_text = text + end, +} + +-- called with the 'name' entry +local function optcontrol_SetLabel (self, text) + local name, desc = ('\t'):split(text) + if desc then + self:SetEditBoxTooltip(desc) + end + self.editbox:SetLabel(name) +end + +local function optcontrol_SetValue (self, epcallback) + -- set the callback + self:SetCallback("OnTextEnterPressed", epcallback) + -- remove the fake entry from the values table + self.list[epcallback] = nil +end + + +local function Constructor(is_option_control) + local num = AceGUI:GetNextWidgetNum(Type) + + -- Its frame becomes our widget frame, else its frame is never shown. Gluing + -- them together seems a little evil, but it beats making this widget into a + -- formal containter. Inspired by new-style InteractiveLabel. + local editbox = AceGUI:Create("EditBox") + local frame = editbox.frame + editbox:SetHeight(20) + editbox:SetWidth(100) + frame:SetWidth(frame:GetWidth()+6) + editbox:SetCallback("OnEnter", ddEditBox_OnMouseEnter) + editbox:SetCallback("OnLeave", ddEditBox_OnMouseLeave) + editbox:SetCallback("OnEnterPressed", ddEditBox_OnEnterPressed) + editbox.editbox:SetScript("OnEditFocusGained", ddEditBox_Clear) + editbox.editbox:SetScript("OnEditFocusLost", ddEditBox_Reset) + --editbox.editbox:SetScript("OnEscapePressed", ddEditBox_Reset) + + local button = CreateFrame("Button", nil, frame) + button:SetHeight(20) + button:SetWidth(24) + button:SetPoint("LEFT", editbox.frame, "RIGHT", 0, 0) + button:SetNormalTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Up") + button:SetPushedTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Down") + button:SetDisabledTexture("Interface\\ChatFrame\\UI-ChatIcon-ScrollDown-Disabled") + button:SetHighlightTexture("Interface\\Buttons\\UI-Common-MouseHilight","ADD") + button:SetScript("OnClick", Button_OnClick) + button:SetScript("OnEnter", Button_OnEnter) + button:SetScript("OnLeave", ddEditBox_OnMouseLeave) + button.parent = frame + + local dropdown = CreateFrame("Frame", "AceGUI-3.0EditBoxDropDownMenu"..num, nil, "UIDropDownMenuTemplate") + dropdown:Hide() + + local widget = { + editbox = editbox, + button = button, + dropdown = dropdown, + frame = frame, + type = Type + } + for method, func in pairs(methods) do + widget[method] = func + end + editbox.obj, button.obj, dropdown.obj = widget, widget, widget + if is_option_control then + widget.is_option_control = true + widget.SetLabel = optcontrol_SetLabel + widget.SetValue = optcontrol_SetValue + end + + return AceGUI:RegisterAsWidget(widget) +end + +AceGUI:RegisterWidgetType (Type, Constructor, Version) + +AceGUI:RegisterWidgetType (Type.."OptionControl", function() return Constructor(true) end, Version) +