vanilla-wow-addons – Rev 1

Subversion Repositories:
Rev:

AceGUIListBox = AceGUIBorderFrame:new({
        isUnit  = TRUE,

        defaultRowHeight        = 16,
        frameWidthOffset        = 25,
        rowLeftOffset           = 8,
        scrollBarOffset         = 16,
        heightOffset            = 15,
        buttonHeightOffset      = -1
})

function AceGUIListBox:Setup()
        if( not self._def.elements ) then self._def.elements = {} end
        local elements = self._def.elements
        if( not self._def.backdrop ) then self._def.backdrop = "small" end
        elements.Label                  = {type = ACEGUI_FONTSTRING}
        elements.NormalBackdrop = {type = ACEGUI_FRAME}
        elements.SmallBackdrop  = {type = ACEGUI_FRAME}
        elements.ScrollBox              = {
                type    = ACEGUI_SCROLL_FRAME,
                anchors = {
                        topleft         = {
                                xOffset = 10,
                                yOffset = -5
                        },
                        bottomleft      = {
                                xOffset = 10,
                                yOffset = 4
                        },
                        topright        = {
                                xOffset = -27,
                                yOffset = -5
                        },
                        bottomright     = {
                                xOffset = -27,
                                yOffset = 4
                        }
                }
        }
        elements.Spacer                 = {
                type    = ACEGUI_FRAME,
                anchors = {
                        topright        = {xOffset = 0, yOffset = 0},
                        bottomright     = {xOffset = 0, yOffset = 0}
                }
        }
        self:AddRows()
end

function AceGUIListBox:AddRows()
        local r, c = 0, 0
        local prevRow, row, prevCol, col

        self.Rows = {}

        repeat
                r = r + 1
                prevRow = row
                row             = getglobal(self:GetName().."Row"..r)
                if( row ) then
                        self.Rows[r] = row
                        row.Cols = {}
                        self._def.elements["Row"..r] = {
                                type     = ACEGUI_BUTTON,
                                anchors  = {
                                        topleft  = {
                                                relTo    = (prevRow or self):GetName(),
                                                relPoint = prevRow and "bottomleft",
                                                xOffset  = (not prevRow) and self.rowLeftOffset or 0,
                                                yOffset  = (not prevRow) and -8 or self.buttonHeightOffset
                                        },
                                        topright = {
                                                relTo    = prevRow and prevRow:GetName() or "$parentSpacer",
                                                relPoint = prevRow and "bottomright" or "topleft",
                                                xOffset  = 0,
                                                yOffset  = (not prevRow) and -8 or self.buttonHeightOffset
                                        }
                                },
                                elements = {
                                        Highlight               = {type = ACEGUI_TEXTURE},
                                        NormalText              = {type = ACEGUI_FONTSTRING},
                                        HighlightText   = {type = ACEGUI_FONTSTRING},
                                        DisabledText    = {type = ACEGUI_FONTSTRING}
                                }
                        }
                        c       = 1
                        col     = getglobal(row:GetName().."Col"..c)
                        if( col ) then
                                prevCol = nil
                                while( col ) do
                                        self._def.elements["Row"..r].elements["Col"..c] = {
                                                type    = self._def.colTypes
                                                                        and self._def.colTypes[c]
                                                                        or      ACEGUI_BUTTON,
                                                anchors = {
                                                        left = {
                                                                relTo    = (prevCol or row):GetName(),
                                                                relPoint = prevCol and "right",
                                                                xOffset  = prevCol and 0 or 2
                                                        }
                                                },
                                        }
                                        self.Rows[r].Cols[c] = col
                                        col.colID        = c
                                        col.rowIndex = r
                                        if( getglobal(col:GetName().."Text") ) then
                                                self._def.elements["Row"..r].elements["Col"..c].elements = {
                                                        Text = {type = ACEGUI_FONTSTRING}
                                                }
                                        end
                                        col:SetScript("OnClick", function() self:CallHandler("OnItemClick") end)
                                        col:SetScript("OnEnter", function() self:CallHandler("OnItemEnter") end)
                                        col:SetScript("OnLeave", function() self:CallHandler("OnItemLeave") end)

                                        c = c + 1
                                        prevCol = col
                                        col = getglobal(row:GetName().."Col"..c)
                                end
                        else
                                self.Rows[r].Cols[c] = row
                                row.colID        = 1
                                row.rowIndex = r
                                row:SetScript("OnClick", function() self:CallHandler("OnItemClick") end)
                                row:SetScript("OnEnter", function() self:CallHandler("OnItemEnter") end)
                                row:SetScript("OnLeave", function() self:CallHandler("OnItemLeave") end)
                        end
                end
        until( not row )
end

function AceGUIListBox:Configure()
        AceGUIBorderFrame.Configure(self)
        if( self._def.barTexture ) then self.ScrollBox:ShowBarTexture() end
        self:SetLabel()
end

function AceGUIListBox:DynamicSize(w, h)
        if( not w ) then
                w = 0
                for r = 1, getn(self.list), 1 do
                        local width = 0
                        if( (type(self.list[r]) == "table") and (getn(self.list[r]) > 0) ) then
                                for c = 1, getn(self.list[r]) do
                                        width = width + self.Rows[1].Cols[1]:GetWidth()
                                end
                        elseif( self.Rows[1].Cols[1].NormalText ) then
                                self.Rows[1].Cols[1]:SetText(self:GetListText(r))
                                width = width + self.Rows[1].Cols[1].NormalText:GetWidth()
                        elseif( self.Rows[1].Cols[1].Text ) then
                                self.Rows[1].Cols[1]:SetText(self:GetListText(r))
                                width = width + self.Rows[1].Cols[1].Text:GetWidth()
                        end
                        if( width > w ) then w = width end
                end
                w = w + self.frameWidthOffset + self.Spacer:GetWidth()
                if( w < self._def.minWidth ) then w = self._def.minWidth end
        end

        if( not h ) then
                if( getn(self.list) > self.visibleRows ) then
                        h = self.visibleRows * (self.rowHeight + abs(self.buttonHeightOffset)) + self.heightOffset
                else
                        h = getn(self.list) * (self.rowHeight + abs(self.buttonHeightOffset)) + self.heightOffset
                end
        end

        return w, h
end

function AceGUIListBox:Resize(width, height, rh, cw)
        local cwList

        if( not width ) then width = self._def.width end
        if( not height ) then height = self._def.height end
        if( not rh ) then rh = self._def.rowHeight end
        if( not cw ) then cw = self._def.colWidth end

        self.rowHeight = rh or self.defaultRowHeight
        self.ScrollBox.rowHeight = self.rowHeight

        width, height = self:DynamicSize(width, height)

        if( not cw ) then
                cw = floor(
                                (width - self.rowLeftOffset - self.scrollBarOffset)
                                / getn(self.Rows[1].Cols)
                         )
        elseif( type(cw) == "table" ) then
                cwList = cw
                cw = nil
        end

        self:SetWidth(width)
        self:SetHeight(height)

        for r = 1, getn(self.Rows) do
                self.Rows[r]:SetHeight(self.rowHeight)
                for c = 1, getn(self.Rows[r].Cols) do
                        self.Rows[r].Cols[c]:SetWidth(cw or cwList[c])
                        self.Rows[r].Cols[c]:SetHeight(self.rowHeight)
                end
        end
end

function AceGUIListBox:Refresh()
        if( (not self.list) or (self.list ~= self._def.options) ) then
                self.list = self._def.options or self:CallMethod("fill")
        end

        if( not self.list ) then return end

        self.visibleRows = self._def.visibleRows or getn(self.Rows)
        self.totalLines  = getn(self.list)

        if( self.totalLines < self.visibleRows ) then self.visibleRows = self.totalLines end

        for r = 1, getn(self.Rows) do
                if( r <= self.visibleRows ) then
                        self.Rows[r]:Show()
                else
                        self.Rows[r]:Hide()
                end
        end

        if( self.visibleRows < self.totalLines ) then
                self.ScrollBox:SetWidth(self:GetWidth())
                self.ScrollBox:Show()
                self.Spacer:SetWidth(self.scrollBarOffset)
        else
                self.ScrollBox:Hide()
                self.Spacer:SetWidth(1)
        end

        self:Resize()
end

-- Mostly borrowed from FauxScrollFrame_Update()
function AceGUIListBox:UpdateScrollBox()
        if( (self.ScrollBox.ScrollBar:GetValue() or 0) <= 0 ) then
                self.ScrollBox.ScrollBar:SetValue(0)
        end

        local scrollFrameHeight, scrollChildHeight

        if( self.totalLines > 0 ) then
                scrollFrameHeight = (self.totalLines - self.visibleRows) * self.rowHeight
                scrollChildHeight = self.totalLines * self.rowHeight
                if( scrollFrameHeight < 0 ) then
                        scrollFrameHeight = 0
                end
                self.ScrollBox.ScrollChildFrame:Show()
        else
                self.ScrollBox.ScrollChildFrame:Hide()
        end
        self.ScrollBox.ScrollBar:SetMinMaxValues(0, scrollFrameHeight or 0)
        self.ScrollBox.ScrollBar:SetValueStep(self.rowHeight or 0)
        self.ScrollBox.ScrollChildFrame:SetHeight(scrollChildHeight or 0)

        -- Arrow button handling
        if( self.ScrollBox.ScrollBar:GetValue() == 0 ) then
                self.ScrollBox.ScrollBar.ScrollUpButton:Disable()
        else
                self.ScrollBox.ScrollBar.ScrollUpButton:Enable()
        end
        if( (self.ScrollBox.ScrollBar:GetValue() - scrollFrameHeight) == 0) then
                self.ScrollBox.ScrollBar.ScrollDownButton:Disable()
        else
                self.ScrollBox.ScrollBar.ScrollDownButton:Enable()
        end
end

function AceGUIListBox:Update()
        if( (not self.list) or (self.totalLines ~= getn(self.list)) ) then self:Refresh() end
        if( not self.list ) then return end

        local i

        self:UpdateScrollBox()

        if( self._lockedRow ) then self._lockedRow = nil end

        for r = 1, self.visibleRows do
                i = r + self.ScrollBox.offset

                self.Rows[r].rowID = i
                for c = 1, getn(self.Rows[r].Cols) do
                        self.Rows[r].Cols[c]:SetValue(self:GetListText(i, c) or "")
                        self.Rows[r].Cols[c].rowID = i
                        if( self:GetListVal(i, c) == self.selectedValue ) then
                                self:SetSelected(i, c)
                        end
                end
                if( i == self.selectedRowID ) then
                        self.Rows[r].Highlight:Show()
                        self.Rows[r]:LockHighlight()
                        self._lockedRow = self.Rows[r]
                else
                        self.Rows[r].Highlight:Hide()
                        self.Rows[r]:UnlockHighlight()
                end
        end
end

function AceGUIListBox:OnVerticalScroll()
        self.ScrollBox:OnVerticalScroll()
        self:Update()
end

function AceGUIListBox:OnMouseWheel()
        self.ScrollBox:OnMouseWheel()
end


--[[--------------------------------------------------------------------------------
  Values
-----------------------------------------------------------------------------------]]

function AceGUIListBox:GetListText(r, c)
        if( not r ) then return end
        if( type(self.list[r]) == "table" ) then
                return (self.list[r][c or 0] or self.list[r]).text or
                           (self.list[r][c or 0] or self.list[r]).val
        else
                return self.list[r]
        end
end

function AceGUIListBox:GetListVal(r, c)
        if( not r ) then return end
        if( type(self.list[r]) == "table" ) then
                return (self.list[r][c or 0] or self.list[r]).val
        else
                return self.list[r]
        end
end

function AceGUIListBox:GetListTip(r, c)
        if( not r ) then return end
        if( type(self.list[r]) == "table" ) then
                return (self.list[r][c or 0] or self.list[r]).tip
        end
end

function AceGUIListBox:GetValue()
        return self.selectedValue
end

function AceGUIListBox:SetValue(val)
        self.selectedRowID = nil
        self.selectedColID = nil
        self.selectedValue = nil

        if( not val ) then return end

        for r = 1, getn(self.list) do
                if( type(self.list[r]) == "table" ) then
                        for c = 1, getn(self.list[r]) do
                                if( self.GetListVal(r, c) == val ) then
                                        self:SetSelected(r, c)
                                        return
                                end
                        end
                else
                        if( self.GetListVal(r) == val ) then
                                self:SetSelected(r, c)
                                return
                        end
                end
        end
end

function AceGUIListBox:GetSelected()
        return self.selectedRowID, self.selectedColID, self.selectedValue
end

function AceGUIListBox:SetSelected(r, c)
        if( (r == self.selectedRowID) and (c == self.selectedColID) ) then return end

        self.selectedRowID = r
        self.selectedColID = c
        self.selectedValue = self:GetListVal(r, c)
end

function AceGUIListBox:Clear()
        self:SetValue()
end

function AceGUIListBox:ClearList()
        self:SetValue()
        self.ScrollBox:Clear()
        self.list = nil
end


--[[--------------------------------------------------------------------------------
  Events
-----------------------------------------------------------------------------------]]

function AceGUIListBox:OnShow()
        self:Update()
end

function AceGUIListBox:OnItemClick()
        self:CloseDropDowns()

        if( self._lockedRow ) then
                self._lockedRow:UnlockHighlight()
                if( self._lockedRow ~= self.Rows[this.rowIndex] ) then
                        self._lockedRow.Highlight:Hide()
                end
                self._lockedRow = nil
        end

        if( self.selectedRowID ~= this.rowID ) then
                self:SetSelected(this.rowID, this.colID)
                self.Rows[this.rowIndex].Highlight:Show()
                self.Rows[this.rowIndex]:LockHighlight()
                self._lockedRow = self.Rows[this.rowIndex]
        else
                self:SetSelected()
        end

        self:CallHandler("OnSelect")
end

function AceGUIListBox:OnItemEnter()
        local tip = self:GetListTip(this.rowID, this.colID)
        self.Rows[this.rowIndex].Highlight:Show()
        if( tip ) then self:ShowTooltip(self.Rows[this.rowIndex], tip) end
end

function AceGUIListBox:OnItemLeave()
        if( self._lockedRow ~= self.Rows[this.rowIndex] ) then
                self.Rows[this.rowIndex]:UnlockHighlight()
                self.Rows[this.rowIndex].Highlight:Hide()
        end
        if( GameTooltip:IsVisible() ) then GameTooltip:Hide() end
end