315 lines
8.9 KiB
Lua
315 lines
8.9 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- http://www.curse.com/addons/wow/tradeskill-master --
|
|
-- --
|
|
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
|
|
-- All Rights Reserved* - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
-- Much of this code is copied from .../AceGUI-3.0/widgets/AceGUIWidget-Dropdown.lua
|
|
-- This Dropdown-Pullout widget is modified to fit TSM's theme / needs
|
|
local TSM = select(2, ...)
|
|
local AceGUI = LibStub and LibStub("AceGUI-3.0", true)
|
|
local Type, Version = "TSMDropdown-Pullout", 2
|
|
if not AceGUI or (AceGUI:GetWidgetVersion(Type) or 0) >= Version then return end
|
|
|
|
-- Lua APIs
|
|
local min, max, floor = math.min, math.max, math.floor
|
|
local select, pairs, ipairs, type = select, pairs, ipairs, type
|
|
local tsort = table.sort
|
|
|
|
-- WoW APIs
|
|
local PlaySound = PlaySound
|
|
local UIParent, CreateFrame = UIParent, CreateFrame
|
|
local _G = _G
|
|
|
|
|
|
--[[-----------------------------------------------------------------------------
|
|
Globals
|
|
-------------------------------------------------------------------------------]]
|
|
|
|
local sliderBackdrop = {
|
|
bgFile = "Interface\\Buttons\\UI-SliderBar-Background",
|
|
edgeFile = "Interface\\Buttons\\UI-SliderBar-Border",
|
|
tile = true, tileSize = 8, edgeSize = 8,
|
|
insets = { left = 3, right = 3, top = 3, bottom = 3 }
|
|
}
|
|
|
|
local DEFAULT_WIDTH = 200
|
|
local DEFAULT_MAX_HEIGHT = 600
|
|
|
|
|
|
--[[-----------------------------------------------------------------------------
|
|
Support functions
|
|
-------------------------------------------------------------------------------]]
|
|
|
|
local function fixstrata(strata, parent, ...)
|
|
local i = 1
|
|
local child = select(i, ...)
|
|
parent:SetFrameStrata(strata)
|
|
while child do
|
|
fixstrata(strata, child, child:GetChildren())
|
|
i = i + 1
|
|
child = select(i, ...)
|
|
end
|
|
end
|
|
|
|
|
|
--[[-----------------------------------------------------------------------------
|
|
Scripts
|
|
-------------------------------------------------------------------------------]]
|
|
|
|
local function OnEnter(item)
|
|
local self = item.pullout
|
|
for k, v in ipairs(self.items) do
|
|
if v.CloseMenu and v ~= item then
|
|
v:CloseMenu()
|
|
end
|
|
end
|
|
end
|
|
|
|
-- See the note in Constructor() for each scroll related function
|
|
local function OnMouseWheel(this, value)
|
|
this.obj:MoveScroll(value)
|
|
end
|
|
|
|
local function OnScrollValueChanged(this, value)
|
|
this.obj:SetScroll(value)
|
|
end
|
|
|
|
local function OnSizeChanged(this)
|
|
this.obj:FixScroll()
|
|
end
|
|
|
|
|
|
--[[-----------------------------------------------------------------------------
|
|
Methods
|
|
-------------------------------------------------------------------------------]]
|
|
|
|
local methods = {
|
|
["OnAcquire"] = function(self)
|
|
self.frame:SetParent(UIParent)
|
|
end,
|
|
|
|
["OnRelease"] = function(self)
|
|
self:Clear()
|
|
self.frame:ClearAllPoints()
|
|
self.frame:Hide()
|
|
end,
|
|
|
|
["SetScroll"] = function(self, value)
|
|
local status = self.scrollStatus
|
|
local frame, child = self.scrollFrame, self.itemFrame
|
|
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
|
|
|
local offset
|
|
if height > viewheight then
|
|
offset = 0
|
|
else
|
|
offset = floor((viewheight - height) / 1000 * value)
|
|
end
|
|
child:ClearAllPoints()
|
|
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
|
|
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", self.slider:IsShown() and -12 or 0, offset)
|
|
status.offset = offset
|
|
status.scrollvalue = value
|
|
end,
|
|
|
|
["MoveScroll"] = function(self, value)
|
|
local status = self.scrollStatus
|
|
local frame, child = self.scrollFrame, self.itemFrame
|
|
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
|
|
|
if height > viewheight then
|
|
self.slider:Hide()
|
|
else
|
|
self.slider:Show()
|
|
local diff = height - viewheight
|
|
local delta = 1
|
|
if value < 0 then
|
|
delta = -1
|
|
end
|
|
self.slider:SetValue(min(max(status.scrollvalue + delta*(1000/(diff/45)),0), 1000))
|
|
end
|
|
end,
|
|
|
|
["FixScroll"] = function(self)
|
|
local status = self.scrollStatus
|
|
local frame, child = self.scrollFrame, self.itemFrame
|
|
local height, viewheight = frame:GetHeight(), child:GetHeight()
|
|
local offset = status.offset or 0
|
|
|
|
if viewheight < height then
|
|
self.slider:Hide()
|
|
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", 0, offset)
|
|
self.slider:SetValue(0)
|
|
else
|
|
self.slider:Show()
|
|
local value = (offset / (viewheight - height) * 1000)
|
|
if value > 1000 then value = 1000 end
|
|
self.slider:SetValue(value)
|
|
self:SetScroll(value)
|
|
if value < 1000 then
|
|
child:ClearAllPoints()
|
|
child:SetPoint("TOPLEFT", frame, "TOPLEFT", 0, offset)
|
|
child:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -12, offset)
|
|
status.offset = offset
|
|
end
|
|
end
|
|
end,
|
|
|
|
["AddItem"] = function(self, item)
|
|
self.items[#self.items + 1] = item
|
|
|
|
local h = #self.items * 16
|
|
self.itemFrame:SetHeight(h)
|
|
self.frame:SetHeight(min(h + 20, self.maxHeight))
|
|
|
|
item.frame:SetPoint("LEFT", self.itemFrame, "LEFT")
|
|
item.frame:SetPoint("RIGHT", self.itemFrame, "RIGHT")
|
|
|
|
item:SetPullout(self)
|
|
item:SetOnEnter(OnEnter)
|
|
end,
|
|
|
|
["Open"] = function(self, point, relFrame, relPoint, x, y)
|
|
local items = self.items
|
|
local frame = self.frame
|
|
local itemFrame = self.itemFrame
|
|
|
|
frame:SetPoint(point, relFrame, relPoint, x, y)
|
|
|
|
local height = 8
|
|
for i, item in pairs(items) do
|
|
if i == 1 then
|
|
item:SetPoint("TOP", itemFrame, "TOP", 0, -2)
|
|
else
|
|
item:SetPoint("TOP", items[i-1].frame, "BOTTOM", 0, 1)
|
|
end
|
|
|
|
item:Show()
|
|
|
|
height = height + 16
|
|
end
|
|
itemFrame:SetHeight(height)
|
|
fixstrata("TOOLTIP", frame, frame:GetChildren())
|
|
frame:Show()
|
|
self:Fire("OnOpen")
|
|
end,
|
|
|
|
["Close"] = function(self)
|
|
self.frame:Hide()
|
|
self:Fire("OnClose")
|
|
end,
|
|
|
|
["Clear"] = function(self)
|
|
local items = self.items
|
|
for i, item in pairs(items) do
|
|
AceGUI:Release(item)
|
|
items[i] = nil
|
|
end
|
|
end,
|
|
|
|
["IterateItems"] = function(self)
|
|
return ipairs(self.items)
|
|
end,
|
|
|
|
["SetHideOnLeave"] = function(self, val)
|
|
self.hideOnLeave = val
|
|
end,
|
|
|
|
["SetMaxHeight"] = function(self, height)
|
|
self.maxHeight = height or DEFAULT_MAX_HEIGHT
|
|
if self.frame:GetHeight() > height then
|
|
self.frame:SetHeight(height)
|
|
elseif (self.itemFrame:GetHeight()+20) < height then
|
|
self.frame:SetHeight(self.itemFrame:GetHeight()+20) -- see :AddItem
|
|
end
|
|
end,
|
|
|
|
["GetRightBorderWidth"] = function(self)
|
|
return 6 + (self.slider:IsShown() and 12 or 0)
|
|
end,
|
|
|
|
["GetLeftBorderWidth"] = function(self)
|
|
return 6
|
|
end,
|
|
}
|
|
|
|
|
|
--[[-----------------------------------------------------------------------------
|
|
Constructor
|
|
-------------------------------------------------------------------------------]]
|
|
|
|
local function Constructor()
|
|
local count = AceGUI:GetNextWidgetNum(Type)
|
|
|
|
local frame = CreateFrame("Frame", "TSMPullout"..count, UIParent)
|
|
TSMAPI.Design:SetContentColor(frame)
|
|
frame:SetFrameStrata("FULLSCREEN_DIALOG")
|
|
frame:SetClampedToScreen(true)
|
|
frame:SetWidth(DEFAULT_WIDTH)
|
|
frame:SetHeight(DEFAULT_MAX_HEIGHT)
|
|
|
|
local scrollFrame = CreateFrame("ScrollFrame", nil, frame)
|
|
local itemFrame = CreateFrame("Frame", nil, scrollFrame)
|
|
|
|
local slider = CreateFrame("Slider", "TSMPulloutScrollbar"..count, scrollFrame)
|
|
slider:SetOrientation("VERTICAL")
|
|
slider:SetHitRectInsets(0, 0, -10, 0)
|
|
slider:SetBackdrop(sliderBackdrop)
|
|
slider:SetWidth(8)
|
|
slider:SetThumbTexture("Interface\\Buttons\\UI-SliderBar-Button-Vertical")
|
|
slider:SetFrameStrata("FULLSCREEN_DIALOG")
|
|
|
|
scrollFrame:SetScrollChild(itemFrame)
|
|
scrollFrame:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -4)
|
|
scrollFrame:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -4, 4)
|
|
scrollFrame:EnableMouseWheel(true)
|
|
scrollFrame:SetScript("OnMouseWheel", OnMouseWheel)
|
|
scrollFrame:SetScript("OnSizeChanged", OnSizeChanged)
|
|
scrollFrame:SetToplevel(true)
|
|
scrollFrame:SetFrameStrata("FULLSCREEN_DIALOG")
|
|
|
|
itemFrame:SetPoint("TOPLEFT", scrollFrame, "TOPLEFT", 0, 0)
|
|
itemFrame:SetPoint("TOPRIGHT", scrollFrame, "TOPRIGHT", -12, 0)
|
|
itemFrame:SetHeight(400)
|
|
itemFrame:SetToplevel(true)
|
|
itemFrame:SetFrameStrata("FULLSCREEN_DIALOG")
|
|
|
|
slider:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", -16, 0)
|
|
slider:SetPoint("BOTTOMLEFT", scrollFrame, "BOTTOMRIGHT", -16, 0)
|
|
|
|
scrollFrame:Show()
|
|
itemFrame:Show()
|
|
slider:Hide()
|
|
|
|
local widget = {
|
|
frame = frame,
|
|
slider = slider,
|
|
scrollFrame = scrollFrame,
|
|
itemFrame = itemFrame,
|
|
maxHeight = DEFAULT_MAX_HEIGHT,
|
|
scrollStatus = {scrollvalue=0},
|
|
count = count,
|
|
items = {},
|
|
type = Type,
|
|
}
|
|
for method, func in pairs(methods) do
|
|
widget[method] = func
|
|
end
|
|
frame.obj = widget
|
|
scrollFrame.obj = widget
|
|
itemFrame.obj = widget
|
|
slider.obj = widget
|
|
|
|
slider:SetScript("OnValueChanged", OnScrollValueChanged)
|
|
slider:SetMinMaxValues(0, 1000)
|
|
slider:SetValueStep(1)
|
|
slider:SetValue(0)
|
|
widget:FixScroll()
|
|
|
|
return AceGUI:RegisterAsWidget(widget)
|
|
end
|
|
|
|
AceGUI:RegisterWidgetType(Type, Constructor, Version) |