1. Are you planning to upload your awesome spell or system to Hive? Please review the rules here.
    Dismiss Notice
  2. Awaken what lies in the heart of your swarm. The 17th Techtree Contest has arrived!
    Dismiss Notice
  3. The Hive Workshop is launching its first HD modelling contest. How HD should it be?
    Dismiss Notice
  4. Check out the Staff Job Openings thread.
    Dismiss Notice
Dismiss Notice
Hive 3 Remoosed BETA - NOW LIVE. Go check it out at BETA Hive Workshop! Post your feedback in this new forum BETA Feedback.
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

TasButtonList

Submitted by Tasyen
This bundle is marked as approved. It works and satisfies the submission rules.

Introduction


TasButtonList is a UI-Frame Resource, it displays data to a fixed amount of clickable buttons. The idea was to create a System, you feed with data and behaviour, while the UI-Part one has to do (as mapper) is quite low.

Features

Create any amount of TasButtonList at the same Time.
Builtin in are 3 Variations of a ButtonList (1 per row, 2 and 3 per Row)
The currently displayed content can be scrolled.
With search by text one can change the current relevant fraction of data.
customizeable to adapt to custom data.
one can set a custom filter additional to the search by text

How to Install

First you have to export and import the 2 Files in the demo map (using the export all Files function can bug in older Editor Versions).

war3mapImported\TasButtonList.fdf
war3mapImported\TasButtonList.toc​
Now you copy TasButtonList (trigger editor) into your map
if all worked, you can now use it.

  • Examples


    Creates a ButtonList with 8 Buttons, using Unit-RawCodes as data. Which are on default quite well supported.
    When a player clicks a Button the data currently pointed at by that Button is created for the clicking Player at the map center.
    Code (Lua):
    do
        local realFunc = MarkGameStarted
        function MarkGameStarted()
        realFunc()
        xpcall(function()
        -- create an empty Frame that will be the ButtonLists parent. if you want to hide/move the ButtonList hide/move the parent.
        local frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "",0)
        BlzFrameSetSize(frame, 0.23, 0.001)
        BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOP, 0.6, 0.5)
        -- create a new ButtonList with 8 Rows, frame is the parent and define the action when clicking the Button
        local object = CreateTasButtonList(8, frame, function(data, buttonListObject, dataIndex)
            -- create an unit for the clicking player at 0/0 with facing 0
             CreateUnit(GetTriggerPlayer(), data, 0, 0, 0)
        end)
        -- add various data
        TasButtonListAddData(object, FourCC("Hpal"))
        TasButtonListAddData(object, FourCC("Hblm"))
        TasButtonListAddData(object, FourCC("hfoo"))
        TasButtonListAddData(object, FourCC("hkni"))
        TasButtonListAddData(object, FourCC("hdhw"))
        TasButtonListAddData(object, FourCC("hmpr"))
        TasButtonListAddData(object, FourCC("hsor"))
        TasButtonListAddData(object, FourCC("hrif"))
        TasButtonListAddData(object, FourCC("Ofar"))
        TasButtonListAddData(object, FourCC("ogru"))
        TasButtonListAddData(object, FourCC("orai"))
        -- force an update
    --    UpdateTasButtonList(object)
        BlzFrameSetValue(object.Slider, 999999)
        print("done")
        end, print)
        end
    end
    displaying custom Data.
    Code (Lua):
    do
        local realFunc = MarkGameStarted
        function MarkGameStarted()
        realFunc()
        xpcall(function()
            -- create an empty Frame that will be the ButtonLists parent. if you want to hide/move the ButtonList hide/move the parent.
            local frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "",0)
            BlzFrameSetSize(frame, 0.23, 0.001)
            BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOP, 0.6, 0.5)
            -- create a new ButtonList with 4 Rows, frame is the parent and define the action when clicking the Button
            local object = CreateTasButtonList(4, frame, function(data, buttonListObject, dataIndex)
                print(data.Icon, data.Text)
            end,
            function(frameObject, data)
                BlzFrameSetTexture(frameObject.Icon, data.Icon, 0, false)
                BlzFrameSetText(frameObject.Text, data.Text)
     
                BlzFrameSetTexture(frameObject.ToolTipFrameIcon, data.Icon, 0, false)
                BlzFrameSetText(frameObject.ToolTipFrameName, data.Text)
            end)
     
     
            -- add various data
            TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNPriest", Text = "Custom A"})
            TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNSlow", Text = "Custom B"})
            TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNInvisibility", Text = "Custom C"})
            TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNBanish", Text = "Custom D"})
            TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNCrystalBall", Text = "Custom E"})
            TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNBoots", Text = "Custom F"})
            TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNTalisman", Text = "Custom G"})
     
            -- force an update
        --    UpdateTasButtonList(object)
            BlzFrameSetValue(object.Slider, 999999)
     
            print("done")
        end, print)
        end
    end
    There are more examples but for them you need to download the demo map.

    Source code
    Code (Lua):
    --[[
    TasButtonList10 by Tasyen

    function CreateTasButtonListEx(buttonName, cols, rows, parent, buttonAction[, rightClickAction, updateAction, searchAction, filterAction, asyncButtonAction, asyncRightClickAction, colGap, rowGap])
     create a new List
     parent is the container of this Frame it will attach itself to its TOP.
     buttonAction is the function that executes when an option is clicked. args: (clickedData, buttonListObject, dataIndex)
     rightClickAction is the function that executes when an option is rightClicked. args: (clickedData, buttonListObject, dataIndex)
     when your data are object Editor object-RawCodes (but not buffs) then updateAction & searchAction use a default one handling them.
     updateAction runs for each Button and is used to set the diplayed content. args:(frameObject, data)
        frameObject.Button
        frameObject.ToolTipFrame
        frameObject.ToolTipFrameIcon
        frameObject.ToolTipFrameName
        frameObject.ToolTipFrameSeperator
        frameObject.ToolTipFrameText

        frameObject.Icon
        frameObject.Text
        frameObject.IconGold
        frameObject.TextGold
        frameObject.IconLumber
        frameObject.TextLumber
        TasButtonList[frameObject] => buttonListObject

        data is one entry of the TasButtonLists Data-Array.

     searchAction is a function that returns true if the current data matches the searchText. Args: (data, searchedText, buttonListObject)
     filterAction is meant to be used when one wants an addtional non text based filtering, with returning true allowing data or false rejecting it. Args: (data, buttonListObject, isTextSearching)
     searchAction , udateAction & filterAction are async this functions should not do anything that alters the game state/flow.
    function CreateTasButtonList(buttonCount, parent, buttonAction[, updateAction, searchAction, filterAction])
        wrapper for CreateTasButtonListEx, 1 col, buttonCount rows.
    function CreateTasButtonListV2(rowCount, parent, buttonAction[, updateAction, searchAction, filterAction])
        wrapper for CreateTasButtonListEx, 2 Buttons each Row, takes more Height then the other Versions
    function CreateTasButtonListV3(rowCount, parent, buttonAction[, updateAction, searchAction, filterAction])
        wrapper for CreateTasButtonListEx, 3 Buttons each Row, only Icon, and Costs

    function TasButtonListClearData(buttonListObject[, player])
        remove all data
    function TasButtonListRemoveData(buttonListObject, data[, player])
        search for data and remove it
    function TasButtonListAddData(buttonListObject, data[, player])
        add data for one Button
    function TasButtonListCopyData(writeObject, readObject[, player])
        writeObject uses the same data as readObject and calls UpdateButtonList.
        The copier writeObject still has an own filtering and searching.
    function UpdateTasButtonList(buttonListObject)
        update the displayed Content should be done after Data was added or removed was used.
    TasButtonListSearch(buttonListObject[, text])
        The buttonList will search it's data for the given text, if nil is given as text it will search for what the user currently has in its box.
        This will also update the buttonList
    --]]


    TasButtonList = {}

    do
        local function reload()
            BlzLoadTOCFile("war3mapimported\\TasButtonList.toc")
        end
        local realFunc = InitBlizzard
        function InitBlizzard()
            realFunc()
            reload()
            if FrameLoaderAdd then FrameLoaderAdd(reload) end

            TasButtonList.SyncTrigger = CreateTrigger()
            TasButtonList.SyncTriggerAction = TriggerAddAction(TasButtonList.SyncTrigger, function()
                xpcall(function()
                local buttonListObject = TasButtonList[BlzGetTriggerFrame()]
                local dataIndex = math.tointeger(BlzGetTriggerFrameValue())

                if buttonListObject.ButtonAction then
                    -- call the wanted action, 1 the current Data
                    buttonListObject.ButtonAction(buttonListObject.Data[GetTriggerPlayer()][dataIndex], buttonListObject, dataIndex)
                end
                UpdateTasButtonList(buttonListObject)
                end,print)
            end)

            TasButtonList.SyncTriggerRightClick = CreateTrigger()
            TasButtonList.SyncTriggerRightClickAction = TriggerAddAction(TasButtonList.SyncTriggerRightClick, function()
                xpcall(function()
                local buttonListObject = TasButtonList[BlzGetTriggerFrame()]
                local dataIndex = math.tointeger(BlzGetTriggerFrameValue())

                if buttonListObject.RightClickAction then
                    -- call the wanted action, 1 the current Data
                    buttonListObject.RightClickAction(buttonListObject.Data[GetTriggerPlayer()][dataIndex], buttonListObject, dataIndex)
                end
                UpdateTasButtonList(buttonListObject)
                end,print)
            end)

            TasButtonList.RightClickSound = CreateSound("Sound\\Interface\\MouseClick1.wav", false, false, false, 10, 10, "")
            SetSoundParamsFromLabel(TasButtonList.RightClickSound, "InterfaceClick")
            SetSoundDuration(TasButtonList.RightClickSound, 239)

            -- handles the clicking
            TasButtonList.ButtonTrigger = CreateTrigger()
            TasButtonList.ButtonTriggerAction = TriggerAddAction(TasButtonList.ButtonTrigger, function()
                local frame = BlzGetTriggerFrame()
                local buttonIndex = TasButtonList[frame].Index
                local buttonListObject = TasButtonList[TasButtonList[frame]]
                local dataIndex = buttonListObject.DataFiltered[buttonListObject.ViewPoint + buttonIndex]
                BlzFrameSetEnable(frame, false)
                BlzFrameSetEnable(frame, true)
                if GetLocalPlayer() == GetTriggerPlayer() then
                    if buttonListObject.AsyncButtonAction then
                        buttonListObject.AsyncButtonAction(buttonListObject, buttonListObject.Data[GetLocalPlayer()][R2I(dataIndex)], frame)
                    end
                    BlzFrameSetValue(buttonListObject.SyncFrame, dataIndex)
                end
            end)

            -- handles the clicking
            TasButtonList.ButtonTriggerRightClick = CreateTrigger()
            TasButtonList.ButtonTriggerRightClickAction = TriggerAddAction(TasButtonList.ButtonTriggerRightClick, function()
                local frame = BlzGetTriggerFrame()
                local buttonIndex = TasButtonList[frame].Index
                local buttonListObject = TasButtonList[TasButtonList[frame]]
                local dataIndex = buttonListObject.DataFiltered[buttonListObject.ViewPoint + buttonIndex]
                if IsRightClick(GetTriggerPlayer()) and GetLocalPlayer() == GetTriggerPlayer() then
                    if buttonListObject.AsyncRightClickAction then
                        buttonListObject.AsyncRightClickAction(buttonListObject, buttonListObject.Data[GetLocalPlayer()][R2I(dataIndex)], frame)
                    end
                    StartSound(TasButtonList.RightClickSound)
                    BlzFrameSetValue(buttonListObject.SyncFrameRightClick, dataIndex)
                end
            end)

            TasButtonList.SearchTrigger = CreateTrigger()
            TasButtonList.SearchTriggerAction = TriggerAddAction(TasButtonList.SearchTrigger, function()
                TasButtonListSearch(TasButtonList[BlzGetTriggerFrame()], BlzFrameGetText(BlzGetTriggerFrame()))
            end)

            -- scrolling while pointing on Buttons
            TasButtonList.ButtonScrollTrigger = CreateTrigger()
            TasButtonList.ButtonScrollTriggerAction = TriggerAddAction(TasButtonList.ButtonScrollTrigger, function()
                local buttonListObject = TasButtonList[TasButtonList[BlzGetTriggerFrame()]]
                local frame = buttonListObject.Slider
                if GetLocalPlayer() == GetTriggerPlayer() then
                    if BlzGetTriggerFrameValue() > 0 then
                        BlzFrameSetValue(frame, BlzFrameGetValue(frame) + buttonListObject.SliderStep)
                    else
                        BlzFrameSetValue(frame, BlzFrameGetValue(frame) - buttonListObject.SliderStep)
                    end
                end
            end)

            -- scrolling while pointing on slider aswell as calling
            TasButtonList.SliderTrigger = CreateTrigger()
            TasButtonList.SliderTriggerAction = TriggerAddAction(TasButtonList.SliderTrigger, function()
                local buttonListObject = TasButtonList[BlzGetTriggerFrame()]
                local frame = BlzGetTriggerFrame()
                if GetLocalPlayer() == GetTriggerPlayer() then
                    if BlzGetTriggerFrameEvent() == FRAMEEVENT_MOUSE_WHEEL then
                        if BlzGetTriggerFrameValue() > 0 then
                            BlzFrameSetValue(frame, BlzFrameGetValue(frame) + buttonListObject.SliderStep)
                        else
                            BlzFrameSetValue(frame, BlzFrameGetValue(frame) - buttonListObject.SliderStep)
                        end
                    else
                        -- when there is enough data use viewPoint. the Viewpoint is reduced from the data to make top being top.
                        if buttonListObject.DataFiltered.Count > buttonListObject.Frames.Count then
                            buttonListObject.ViewPoint = buttonListObject.DataFiltered.Count - math.tointeger(BlzGetTriggerFrameValue())
                        else
                            buttonListObject.ViewPoint = 0
                        end
                        UpdateTasButtonList(buttonListObject)
                    end
                end
            end)
        end
    end
    --runs once for each button shown
    function UpdateTasButtonListDefaultObject(frameObject, data)
        BlzFrameSetTexture(frameObject.Icon, BlzGetAbilityIcon(data), 0, false)
        BlzFrameSetText(frameObject.Text, GetObjectName(data))

        BlzFrameSetTexture(frameObject.ToolTipFrameIcon, BlzGetAbilityIcon(data), 0, false)
        BlzFrameSetText(frameObject.ToolTipFrameName, GetObjectName(data))    
    --        frameObject.ToolTipFrameSeperator
        BlzFrameSetText(frameObject.ToolTipFrameText, BlzGetAbilityExtendedTooltip(data, 0))

        if not IsUnitIdType(data, UNIT_TYPE_HERO) then
            local lumber = GetUnitWoodCost(data)
            local gold = GetUnitGoldCost(data)
            if GetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_GOLD) >= gold then
                BlzFrameSetText(frameObject.TextGold, GetUnitGoldCost(data))
            else
                BlzFrameSetText(frameObject.TextGold, "|cffff2010"..GetUnitGoldCost(data))
            end  
           
            if GetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_LUMBER) >= lumber then
                BlzFrameSetText(frameObject.TextLumber, GetUnitWoodCost(data))
            else
                BlzFrameSetText(frameObject.TextLumber, "|cffff2010"..GetUnitWoodCost(data))
            end
        else
            BlzFrameSetText(frameObject.TextLumber, 0)
            BlzFrameSetText(frameObject.TextGold, 0)
        end
    end

    function SearchTasButtonListDefaultObject(data, searchedText, buttonListObject)
        --return BlzGetAbilityTooltip(data, 0)
        --return GetObjectName(data, 0)
        --return string.find(GetObjectName(data), searchedText)
        return string.find(string.lower(GetObjectName(data)), string.lower(searchedText))
    end

    -- update the shown content
    function UpdateTasButtonList(buttonListObject)
        xpcall(function()
        local data = buttonListObject.Data[GetLocalPlayer()]
        BlzFrameSetVisible(buttonListObject.Slider, buttonListObject.DataFiltered.Count > buttonListObject.Frames.Count)
        for int = 1, buttonListObject.Frames.Count do
            local frameObject = buttonListObject.Frames[int]
            if buttonListObject.DataFiltered.Count >= int  then
                buttonListObject.UpdateAction(frameObject, data[buttonListObject.DataFiltered[int + buttonListObject.ViewPoint]])
                BlzFrameSetVisible(frameObject.Button, true)
            else
                BlzFrameSetVisible(frameObject.Button, false)
            end
        end
    end, print)
    end

    -- for backwards compatibility rightClickAction is the last argument
    function InitTasButtonListObject(parent, buttonAction, updateAction, searchAction, filterAction, rightClickAction, asyncButtonAction, asyncRightClickAction)
        local object = {
            Data = {}, --an array each slot is the user data
            DataFiltered = {Count = 0}, -- indexes of Data fitting the current search
            ViewPoint = 0,
            Frames = {},
            Parent = parent
        }
        for index = 0, bj_MAX_PLAYER_SLOTS - 1 do
            object.Data[Player(index)] = {Count = 0}
        end
        object.ButtonAction = buttonAction --call this inside the SyncAction after a button is clicked
        object.RightClickAction = rightClickAction -- this inside a SyncAction when the button is right clicked.
        object.UpdateAction = updateAction --function defining how to display stuff (async)
        object.SearchAction = searchAction --function to return the searched Text (async)
        object.FilterAction = filterAction --
        object.AsyncButtonAction = asyncButtonAction -- happens in the clicking event inside a LocalPlayer Block
        object.AsyncRightClickAction = asyncRightClickAction -- happens in the clicking event inside a LocalPlayer Block
        if not updateAction then object.UpdateAction = UpdateTasButtonListDefaultObject end
        if not searchAction then object.SearchAction = SearchTasButtonListDefaultObject end
        table.insert(TasButtonList, object) --index to TasButtonList
        TasButtonList[object] = #TasButtonList -- TasButtonList to Index

        object.SyncFrame = BlzCreateFrameByType("SLIDER", "", parent, "", 0)
        BlzFrameSetMinMaxValue(object.SyncFrame, 0, 9999999)
        BlzFrameSetStepSize(object.SyncFrame, 1.0)
        BlzTriggerRegisterFrameEvent(TasButtonList.SyncTrigger, object.SyncFrame, FRAMEEVENT_SLIDER_VALUE_CHANGED)
        BlzFrameSetVisible(object.SyncFrame, false)
        TasButtonList[object.SyncFrame] = object

        object.SyncFrameRightClick = BlzCreateFrameByType("SLIDER", "", parent, "", 0)
        BlzFrameSetMinMaxValue(object.SyncFrameRightClick, 0, 9999999)
        BlzFrameSetStepSize(object.SyncFrameRightClick, 1.0)
        BlzTriggerRegisterFrameEvent(TasButtonList.SyncTriggerRightClick, object.SyncFrameRightClick, FRAMEEVENT_SLIDER_VALUE_CHANGED)
        BlzFrameSetVisible(object.SyncFrameRightClick, false)
        TasButtonList[object.SyncFrameRightClick] = object

        object.InputFrame = BlzCreateFrame("TasEditBox", parent, 0, 0)
        BlzTriggerRegisterFrameEvent(TasButtonList.SearchTrigger, object.InputFrame, FRAMEEVENT_EDITBOX_TEXT_CHANGED)
        BlzFrameSetPoint(object.InputFrame, FRAMEPOINT_TOPRIGHT, parent, FRAMEPOINT_TOPRIGHT, 0, 0)
        TasButtonList[object.InputFrame] = object

        return object
    end

    function InitTasButtonListSlider(object, stepSize, rowCount)
        object.Slider = BlzCreateFrameByType("SLIDER", "FrameListSlider", object.Parent, "QuestMainListScrollBar", 0)
        TasButtonList[object.Slider] = object -- the slider nows the TasButtonListobject
        object.SliderStep = stepSize
        BlzFrameSetStepSize(object.Slider, stepSize)
        BlzFrameClearAllPoints(object.Slider)
        BlzFrameSetVisible(object.Slider, true)
        BlzFrameSetMinMaxValue(object.Slider, 0, 0)
        BlzFrameSetPoint(object.Slider, FRAMEPOINT_TOPLEFT, object.Frames[1].Button, FRAMEPOINT_TOPRIGHT, 0, 0)
        BlzFrameSetSize(object.Slider, 0.012, BlzFrameGetHeight(object.Frames[1].Button) * rowCount)
        BlzTriggerRegisterFrameEvent(TasButtonList.SliderTrigger, object.Slider , FRAMEEVENT_SLIDER_VALUE_CHANGED)
        BlzTriggerRegisterFrameEvent(TasButtonList.SliderTrigger, object.Slider , FRAMEEVENT_MOUSE_WHEEL)
    end

    function TasButtonListAddDataEx(buttonListObject, data, player)
        local oData = buttonListObject.Data[player]
        local oDataFil = buttonListObject.DataFiltered
       
        oData.Count = oData.Count + 1
        oData[oData.Count] = data
        if GetLocalPlayer() == player then
            -- filterData is a local thing
            oDataFil.Count = oDataFil.Count + 1
            oDataFil[oDataFil.Count] = oData.Count
            BlzFrameSetMinMaxValue(buttonListObject.Slider, buttonListObject.Frames.Count, oDataFil.Count)
        end
    end

    function TasButtonListAddData(buttonListObject, data, player)
        if player and type(player) == "userdata" then
            TasButtonListAddDataEx(buttonListObject, data, player)
        else
            for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
                TasButtonListAddDataEx(buttonListObject, data, Player(i))
            end
        end
    end

    function TasButtonListRemoveDataEx(buttonListObject, data, player)
        local oData = buttonListObject.Data[player]
        for index = 1, oData.Count do
            value = oData[index]
            if value == data then
                oData[index] = oData[oData.Count]
                oData.Count = oData.Count - 1
                break
            end
        end
        if GetLocalPlayer() == player then
            BlzFrameSetMinMaxValue(buttonListObject.Slider, buttonListObject.Frames.Count, oData.Count)
        end
    end

    function TasButtonListRemoveData(buttonListObject, data, player)
        if player and type(player) == "userdata" then
            TasButtonListRemoveDataEx(buttonListObject, data, player)
        else
            for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
                TasButtonListRemoveDataEx(buttonListObject, data, Player(i))
            end
        end
    end

    function TasButtonListClearDataEx(buttonListObject, player)
        buttonListObject.Data[player].Count = 0
        if GetLocalPlayer() == player then
            buttonListObject.DataFiltered.Count = 0
            BlzFrameSetMinMaxValue(buttonListObject.Slider, 0, 0)
        end
    end

    function TasButtonListClearData(buttonListObject, player)
        if player and type(player) == "userdata" then
            TasButtonListClearDataEx(buttonListObject, player)
        else
            for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
                TasButtonListClearDataEx(buttonListObject, Player(i))
            end
        end
    end

    function TasButtonListCopyDataEx(writeObject, readObject, player)
        writeObject.Data[player] = readObject.Data[player]
        for index = 1, readObject.DataFiltered.Count do writeObject.DataFiltered[index] = readObject.DataFiltered[index] end
        writeObject.DataFiltered.Count = readObject.DataFiltered.Count
        if GetLocalPlayer() == player then
            BlzFrameSetMinMaxValue(writeObject.Slider, writeObject.Frames.Count, writeObject.Data[player].Count)
            BlzFrameSetValue(writeObject.Slider,999999)
        end
       
    end

    function TasButtonListCopyData(writeObject, readObject, player)
        if player and type(player) == "userdata" then
            TasButtonListCopyDataEx(writeObject, readObject, player)
        else
            for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
                TasButtonListCopyDataEx(writeObject, readObject, Player(i))
            end
        end
    end

    function TasButtonListSearch(buttonListObject, text)
        if not text then text = BlzFrameGetText(buttonListObject.InputFrame) end
        local filteredData = buttonListObject.DataFiltered
        local oData = buttonListObject.Data[GetLocalPlayer()]
        local value
        if GetLocalPlayer() == GetTriggerPlayer() then
            filteredData.Count = 0
            if text ~= "" then
                for index = 1, oData.Count do
                    value = oData[index]
                    if buttonListObject.SearchAction(value, text, buttonListObject) and (not buttonListObject.FilterAction or buttonListObject.FilterAction(value, buttonListObject, true)) then
                        filteredData.Count = filteredData.Count + 1
                        filteredData[filteredData.Count] = index
                    end
                end
               
            else
                for index = 1, oData.Count do
                    value = oData[index]
                    if not buttonListObject.FilterAction or buttonListObject.FilterAction(value, buttonListObject, false) then
                        filteredData.Count = filteredData.Count + 1
                        filteredData[filteredData.Count] = index
                    end
                end
            end
            --table.sort(filteredData, function(a, b) return GetObjectName(buttonListObject.Data[a]) < GetObjectName(buttonListObject.Data[b]) end  )
            --update Slider, with that also update
            BlzFrameSetMinMaxValue(buttonListObject.Slider, buttonListObject.Frames.Count, math.max(filteredData.Count,0))
            BlzFrameSetValue(buttonListObject.Slider, 999999)
           
        end
    end

    -- demo Creators
    function CreateTasButtonTooltip(frameObject, parent)
        frameObject.ToolTipFrame = BlzCreateFrame("TasButtonListTooltipBox", frameObject.Button, 0, 0)
        frameObject.ToolTipFrameIcon = BlzGetFrameByName("TasButtonListTooltipIcon", 0)
        frameObject.ToolTipFrameName = BlzGetFrameByName("TasButtonListTooltipName", 0)
        frameObject.ToolTipFrameSeperator = BlzGetFrameByName("TasButtonListTooltipSeperator", 0)
        frameObject.ToolTipFrameText = BlzGetFrameByName("TasButtonListTooltipText", 0)  
        BlzFrameSetPoint(frameObject.ToolTipFrameText, FRAMEPOINT_TOPRIGHT, parent, FRAMEPOINT_TOPLEFT, -0.001, -0.052)
        BlzFrameSetPoint(frameObject.ToolTipFrame, FRAMEPOINT_TOPLEFT, frameObject.ToolTipFrameIcon, FRAMEPOINT_TOPLEFT, -0.005, 0.005)
        BlzFrameSetPoint(frameObject.ToolTipFrame, FRAMEPOINT_BOTTOMRIGHT, frameObject.ToolTipFrameText, FRAMEPOINT_BOTTOMRIGHT, 0.005, -0.005)
        BlzFrameSetTooltip(frameObject.Button, frameObject.ToolTipFrame)
    end

    function CreateTasButtonListEx(buttonName, cols, rows, parent, buttonAction, rightClickAction, updateAction, searchAction, filterAction, asyncButtonAction, asyncRightClickAction, colGap, rowGap)
        if not rowGap then rowGap = 0.0 end
        if not colGap then colGap = 0.0 end
        local buttonCount = rows*cols
        local object = InitTasButtonListObject(parent, buttonAction, updateAction, searchAction, filterAction, rightClickAction, asyncButtonAction, asyncRightClickAction)
        object.Frames.Count = buttonCount
        local rowRemain = cols
        for int = 1, buttonCount do
            local frameObject = {}
            frameObject.Index = int
            frameObject.Button = BlzCreateFrame(buttonName, parent, 0, 0)
            if GetHandleId(frameObject.Button) == 0 then print("TasButtonList - Error - can't create Button:", buttonName) end
            CreateTasButtonTooltip(frameObject, parent)

            frameObject.Icon = BlzGetFrameByName("TasButtonIcon", 0)
            frameObject.Text = BlzGetFrameByName("TasButtonText", 0)
            frameObject.IconGold = BlzGetFrameByName("TasButtonIconGold", 0)
            frameObject.TextGold = BlzGetFrameByName("TasButtonTextGold", 0)
            frameObject.IconLumber = BlzGetFrameByName("TasButtonIconLumber", 0)
            frameObject.TextLumber = BlzGetFrameByName("TasButtonTextLumber", 0)
            TasButtonList[frameObject.Button] = frameObject
            TasButtonList[frameObject] = object
            object.Frames[int] = frameObject
            BlzTriggerRegisterFrameEvent(TasButtonList.ButtonTrigger, frameObject.Button, FRAMEEVENT_CONTROL_CLICK)
            BlzTriggerRegisterFrameEvent(TasButtonList.ButtonTriggerRightClick, frameObject.Button, FRAMEEVENT_MOUSE_UP)
            BlzTriggerRegisterFrameEvent(TasButtonList.ButtonScrollTrigger, frameObject.Button, FRAMEEVENT_MOUSE_WHEEL)
           
            if int > 1 then
                if rowRemain == 0 then
                    BlzFrameSetPoint(frameObject.Button, FRAMEPOINT_TOP, object.Frames[int - cols].Button, FRAMEPOINT_BOTTOM, 0, -rowGap)
                    rowRemain = cols
                else
                    BlzFrameSetPoint(frameObject.Button, FRAMEPOINT_RIGHT, object.Frames[int - 1].Button, FRAMEPOINT_LEFT, -colGap, 0)
                end
            else
                BlzFrameSetPoint(frameObject.Button, FRAMEPOINT_TOPRIGHT, object.InputFrame, FRAMEPOINT_BOTTOMRIGHT, 0, 0)
            end
            rowRemain = rowRemain - 1
        end
        InitTasButtonListSlider(object, cols, rows)

        return object
    end

    function CreateTasButtonList(buttonCount, parent, buttonAction, updateAction, searchAction, filterAction)
        return CreateTasButtonListEx("TasButton", 1, buttonCount, parent, buttonAction, nil, updateAction, searchAction, filterAction)
    end

    function CreateTasButtonListV2(rowCount, parent, buttonAction, updateAction, searchAction, filterAction)
        return CreateTasButtonListEx("TasButtonSmall", 2, rowCount, parent, buttonAction, nil, updateAction, searchAction, filterAction)
    end

    function CreateTasButtonListV3(rowCount, parent, buttonAction, updateAction, searchAction, filterAction)
        return CreateTasButtonListEx("TasButtonGrid", 3, rowCount, parent, buttonAction, nil, updateAction, searchAction, filterAction)
    end

  • The jass version uses library String from MaskedPoptart.

    Example:
    Creates a ButtonList with 8 Buttons, using Unit-RawCodes as data. Which are on default quite well supported.
    When a player clicks a Button the data currently pointed at by that Button is created for the clicking Player at the map center.
    Code (vJASS):

    library SomeTest initializer init_function requires TasButtonList
    private function OnClick takes nothing returns nothing
            // create an unit for the clicking player at 0/0 with facing 0
            call CreateUnit(GetTriggerPlayer(), TasButtonListData, 0, 0, 0)
    endfunction
    private function test takes nothing returns nothing
        // create an empty Frame that will be the ButtonLists parent. if you want to hide/move the ButtonList hide/move the parent.
        local framehandle frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "",0)
        local integer objectIndex = CreateTasButtonList(8, frame, function OnClick, null,null,null)
        call BlzFrameSetSize(frame, 0.23, 0.001)
        call BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOP, 0.6, 0.5)
     
        // add various data
        call TasButtonListAddData(objectIndex, 'Hpal')
        call TasButtonListAddData(objectIndex, 'Hblm')
        call TasButtonListAddData(objectIndex, 'hfoo')
        call TasButtonListAddData(objectIndex, 'hkni')
        call TasButtonListAddData(objectIndex, 'hdhw')
        call TasButtonListAddData(objectIndex, 'hmpr')
        call TasButtonListAddData(objectIndex, 'hsor')
        call TasButtonListAddData(objectIndex, 'hrif')
        call TasButtonListAddData(objectIndex, 'Ofar')
        call TasButtonListAddData(objectIndex, 'ogru')
        call TasButtonListAddData(objectIndex, 'orai')
        // force an update
        call UpdateTasButtonList(objectIndex)
     
        call DestroyTimer(GetExpiredTimer())
    endfunction
        private function init_function takes nothing returns nothing
           call TimerStart(CreateTimer(), 0.0, false, function test)
        endfunction
    endlibrary

    Shows how one could handle custom Data in the (v)jass version. The data is stored in arrays then one adds the indexes of the wanted data into the ButtonList.
    when using custom data one also needs to set the update & search action, additional to the buttonAction.
    Without the update function the buttons will show nonsense and without a search action the user can not search the data.
    Code (vJASS):

    library SomeTest initializer init_function requires TasButtonList
    globals
     
        private string array Icon
        private string array Text
    endglobals
    private function OnClick takes nothing returns nothing
        call BJDebugMsg(I2S(TasButtonListData) + " "+ Text[TasButtonListData])
    endfunction
    private function OnSearch takes nothing returns boolean
        return FindIndex(Text[TasButtonListData], TasButtonListText) >= 0
    endfunction
    private function OnUpdate takes nothing returns nothing
        local integer dataIndex = TasButtonListData
        local integer frameHandle = GetHandleId(TasButtonListFrame)
        call BlzFrameSetTexture(LoadFrameHandle(TasButtonList_Hash, frameHandle, StringHash("Icon")), Icon[dataIndex], 0, false)
        call BlzFrameSetText(LoadFrameHandle(TasButtonList_Hash, frameHandle, StringHash("Text")), Text[dataIndex])
        call BlzFrameSetTexture(LoadFrameHandle(TasButtonList_Hash, frameHandle, StringHash("ToolTipFrameIcon")), Icon[dataIndex], 0, false)
        call BlzFrameSetText(LoadFrameHandle(TasButtonList_Hash, frameHandle, StringHash("ToolTipFrameName")), Text[dataIndex])
    endfunction

    private function test takes nothing returns nothing
        // create an empty Frame that will be the ButtonLists parent. if you want to hide/move the ButtonList hide/move the parent.
     
        local framehandle frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), "",0)
     
        local integer objectIndex = CreateTasButtonList(3, frame, function OnClick, function OnUpdate, function OnSearch, null)
        call BlzFrameSetSize(frame, 0.23, 0.001)
        call BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOP, 0.6, 0.5)
            set Icon[1] = "ReplaceableTextures\\CommandButtons\\BTNPriest"
            set Text[1] = "Custom A"
            set Icon[2] = "ReplaceableTextures\\CommandButtons\\BTNSlow"
            set Text[2] = "Custom B"
            set Icon[3] = "ReplaceableTextures\\CommandButtons\\BTNInvisibility"
            set Text[3] = "Custom C"
            set Icon[4] = "ReplaceableTextures\\CommandButtons\\BTNBanish"
            set Text[4] = "Custom D"
            set Icon[5] = "ReplaceableTextures\\CommandButtons\\BTNCrystalBall"
            set Text[5] = "Custom E"
            set Icon[6] = "ReplaceableTextures\\CommandButtons\\BTNBoots"
            set Text[6] = "Custom F"
            set Icon[7] = "ReplaceableTextures\\CommandButtons\\BTNTalisman"
            set Text[7] = "Custom G"
            call TasButtonListAddData(objectIndex, 1)
            call TasButtonListAddData(objectIndex, 2)
            call TasButtonListAddData(objectIndex, 3)
            call TasButtonListAddData(objectIndex, 4)
            call TasButtonListAddData(objectIndex, 5)
            call TasButtonListAddData(objectIndex, 6)
     
        // force an update
        call UpdateTasButtonList(objectIndex)
     
        call DestroyTimer(GetExpiredTimer())
     
    endfunction
        private function init_function takes nothing returns nothing
     
           call TimerStart(CreateTimer(), 0.0, false, function test)
             // this adds an checkbox, when the checkbox is checked only heroes are valid search targets
     
     
        endfunction
    endlibrary
     
    Code (vJASS):
    native GetUnitGoldCost takes integer rawCode returns integer
    native GetUnitWoodCost takes integer rawCode returns integer

    library TasButtonList initializer Init uses String, IsRightClick
    // TasButtonList10a by Tasyen

    //function CreateTasButtonList10 takes string buttonName, integer cols, integer rows, framehandle parent, code buttonAction, code rightClickAction, code updateAction, code searchAction, code filterAction, code asyncAction, code asyncRigthAction, real colGap, real rowGap returns integer
    //function CreateTasButtonListEx takes string buttonName, integer cols, integer rows, framehandle parent, code buttonAction, code rightClickAction, code updateAction, code searchAction, code filterAction returns integer
     //create a new List
     //parent is the container of this Frame it will attach itself to its TOP.
     //the given functions are called over Triggers
     //buttonAction is the function that executes when an option is clicked.
     //when your data are unit-RawCodes then you can skip updateAction & searchAction.
     //updateAction runs for each Button and is used to set the diplayed content.

     //searchAction is a function that returns true if the current data matches the searchText.
     //filterAction is meant to be used when one wants an addtional non text based filtering, with returning true allowing data or false rejecting it.
     //searchAction , udateAction & filterAction are async this functions should not do anything that alters the game state/flow.

    //function CreateTasButtonList takes integer buttonCount, framehandle parent, code buttonAction, code updateAction, code searchAction, code filterAction returns integer
      // wrapper for CreateTasButtonListEx, 1 col, buttonCount rows.
    //function CreateTasButtonListV2 takes integer rowCount, framehandle parent, code buttonAction, code updateAction, code searchAction, code filterAction returns integer
      //  2 Buttons each Row, takes more Height then the other Versions
    //function CreateTasButtonListV3 takes integer rowCount, framehandle parent, code buttonAction, code updateAction, code searchAction, code filterAction returns integer
      //  3 Buttons each Row, only Icon, and Costs

    //function TasButtonListClearDataEx takes integer listIndex, integer playerIndex returns nothing
    //function TasButtonListClearData takes integer listIndex returns nothing
      //  remove all data
    //function TasButtonListRemoveDataEx takes integer listIndex, integer data, integer playerIndex returns nothing
    //function TasButtonListRemoveData takes integer listIndex, integer data returns nothing
      //  search for data and remove it
    //function TasButtonListAddDataEx takes integer listIndex, integer data, integer playerIndex returns nothing
    //function TasButtonListAddData takes integer listIndex, integer data returns nothing
      //  add data for one Button
    //function TasButtonListCopyDataEx takes integer writeObject, integer readObject, integer playerIndex returns nothing
    //function TasButtonListCopyData takes integer writeObject, integer readObject returns nothing
      //  writeObject uses the same data as readObject and calls UpdateButtonList.
    //function UpdateTasButtonList takes integer listIndex returns nothing
      //  update the displayed Content should be done after Data was added or removed was used.
    //function TasButtonListSearch takes integer listIndex, string text returns nothing
        // The buttonList will search it's data for the given text, if nil is given as text it will search for what the user currently has in its box.
        // This will also update the buttonList

    globals
        //args for custom user actions
        integer TasButtonListData = 0
        string TasButtonListText = ""
        boolean TasButtonListIsSearching = false
        integer TasButtonListIndex = 0
        framehandle TasButtonListFrame = null

        // System
        public hashtable Hash = InitHashtable()
        private integer Counter = 0 //amount of Lists created, each index is one List
        private trigger SyncTrigger = CreateTrigger()
        private trigger ButtonTrigger = CreateTrigger()    
        private trigger SearchTrigger = CreateTrigger()
        private trigger ButtonScrollTrigger = CreateTrigger()
        private trigger SliderTrigger = CreateTrigger()
        private trigger SyncRightTrigger = CreateTrigger()
        private trigger ButtonRightTrigger = CreateTrigger()
        private integer HASH_TOOL_TIP = StringHash("ToolTipFrame")
        private integer HASH_TOOL_TIP_ICON = StringHash("ToolTipFrameIcon")
        private integer HASH_TOOL_TIP_NAME = StringHash("ToolTipFrameName")
        private integer HASH_TOOL_TIP_SEP = StringHash("ToolTipFrameSeperator")
        private integer HASH_TOOL_TIP_TEXT = StringHash("ToolTipFrameText")
        private integer HASH_ICON = StringHash("Icon")
        private integer HASH_TEXT = StringHash("Text")
        private integer HASH_ICON_GOLD = StringHash("IconGold")
        private integer HASH_TEXT_GOLD = StringHash("TextGold")
        private integer HASH_ICON_LUMBER = StringHash("IconLumber")
        private integer HASH_TEXT_LUMBER = StringHash("TextLumber")
        private sound RightClickSound

        // ButtonLists
        framehandle array TasButtonListSlider
        framehandle array TasButtonListParent
        framehandle array TasButtonListInputFrame
        framehandle array TasButtonListSyncFrame
        framehandle array TasButtonListSyncFrameRight
        integer array TasButtonListButtonCount
        integer array TasButtonListStepSize
        trigger array TasButtonListButtonAction
        trigger array TasButtonListRightAction
        trigger array TasButtonListUpdateAction
        trigger array TasButtonListSearchAction
        trigger array TasButtonListFilterAction
        trigger array TasButtonListAsyncAction
        trigger array TasButtonListAsyncRightAction
       
        integer array TasButtonListViewPoint
        location array TasButtonListDataList
        location array TasButtonListDataListFiltered
        location array TasButtonListFrameList

        real TasButtonListGapCol = 0.0
        real TasButtonListGapRow = 0.0

    endglobals


    // update the shown content
    function UpdateTasButtonList takes integer listIndex returns nothing
        local integer dataHash = GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), GetPlayerId(GetLocalPlayer())))
        local integer frameListHash = GetHandleId(TasButtonListFrameList[listIndex])
        local integer filteredDataHash = GetHandleId(TasButtonListDataListFiltered[listIndex])
        local integer dataFilteredCount = LoadInteger(Hash, filteredDataHash, 0)
       
        local integer i = 1

        call BlzFrameSetVisible(TasButtonListSlider[listIndex], dataFilteredCount > TasButtonListButtonCount[listIndex])
        loop
            exitwhen i > TasButtonListButtonCount[listIndex]
            set TasButtonListFrame = LoadFrameHandle(Hash, frameListHash, i)
           
            if dataFilteredCount >= i  then
                set TasButtonListData = LoadInteger(Hash, dataHash, LoadInteger(Hash, filteredDataHash, i + TasButtonListViewPoint[listIndex]))
                call TriggerEvaluate(TasButtonListUpdateAction[listIndex])
                call BlzFrameSetVisible(TasButtonListFrame, true)
            else
                call BlzFrameSetVisible(TasButtonListFrame, false)
            endif
            set i = i + 1
        endloop

    endfunction

    function TasButtonListSearch takes integer listIndex, string text returns nothing
        local integer filteredDataHash = GetHandleId(TasButtonListDataListFiltered[listIndex])
        local integer dataHash = GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), GetPlayerId(GetLocalPlayer())))
        local integer filteredDataCount

        local integer i
        local integer iEnd
        if text == null or text == "" then
            set text = BlzFrameGetText(TasButtonListInputFrame[listIndex])
        endif
        if GetLocalPlayer() == GetTriggerPlayer() then
            set TasButtonListText = text
            set TasButtonListIndex = listIndex
            call FlushChildHashtable(Hash, filteredDataHash)
            set filteredDataCount = 0
            if text != "" then
                set TasButtonListIsSearching = true
                set iEnd = LoadInteger(Hash, dataHash, 0)
                set i = 1
                loop
                    exitwhen i > iEnd
                    set TasButtonListData = LoadInteger(Hash, dataHash, i)
                    if TriggerEvaluate(TasButtonListSearchAction[listIndex]) and TriggerEvaluate(TasButtonListFilterAction[listIndex]) then
                        set filteredDataCount = filteredDataCount + 1
                        call SaveInteger(Hash, filteredDataHash, filteredDataCount, i)
                    endif
                    set i = i + 1
                endloop
                call SaveInteger(Hash, filteredDataHash, 0, filteredDataCount)
            else
                set TasButtonListIsSearching = false
                set iEnd = LoadInteger(Hash, dataHash, 0)
                set i = 1
                loop
                    exitwhen i > iEnd
                    set TasButtonListData = LoadInteger(Hash, dataHash, i)
                    if TriggerEvaluate(TasButtonListFilterAction[listIndex]) then
                        set filteredDataCount = filteredDataCount + 1
                        call SaveInteger(Hash, filteredDataHash, filteredDataCount, i)
                    endif
                    set i = i + 1
                endloop
                call SaveInteger(Hash, filteredDataHash, 0, filteredDataCount)
            endif
           

            //update Slider, with that also update
            call BlzFrameSetMinMaxValue(TasButtonListSlider[listIndex], TasButtonListButtonCount[listIndex], filteredDataCount)
            call BlzFrameSetValue(TasButtonListSlider[listIndex], 999999)
        endif
    endfunction

    function TasButtonListTriggerActionSync takes nothing returns nothing
        local integer listIndex = LoadInteger(Hash, GetHandleId(BlzGetTriggerFrame()), 0)
        local integer dataIndex = R2I(BlzGetTriggerFrameValue() + 0.5)

        set TasButtonListData = LoadInteger(Hash, GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), GetPlayerId(GetTriggerPlayer()))), dataIndex)
        set TasButtonListIndex = listIndex
        call TriggerExecute(TasButtonListButtonAction[listIndex])

        call UpdateTasButtonList(listIndex)
    endfunction

    function TasButtonListTriggerActionButton takes nothing returns nothing
        local framehandle frame = BlzGetTriggerFrame()
        local integer buttonIndex = LoadInteger(Hash, GetHandleId(frame), 1)
        local integer listIndex = LoadInteger(Hash, GetHandleId(frame), 0)
        local integer dataIndex = LoadInteger(Hash, GetHandleId(TasButtonListDataListFiltered[listIndex]), buttonIndex + TasButtonListViewPoint[listIndex])
        local integer data = LoadInteger(Hash, GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), GetPlayerId(GetTriggerPlayer()))), dataIndex)
        call BlzFrameSetEnable(frame, false)
        call BlzFrameSetEnable(frame, true)
        set TasButtonListData = data
        set TasButtonListIndex = listIndex
        set TasButtonListFrame = frame
        if GetLocalPlayer() == GetTriggerPlayer() then
           call TriggerEvaluate(TasButtonListAsyncAction[listIndex])
           call BlzFrameSetValue(TasButtonListSyncFrame[listIndex], dataIndex)
        endif
        set frame = null
    endfunction

    function TasButtonListTriggerActionSearch takes nothing returns nothing
        call TasButtonListSearch(LoadInteger(Hash, GetHandleId(BlzGetTriggerFrame()), 0), null)
    endfunction

    // scrolling while pointing on Buttons
    function TasButtonListTriggerActionButtonScroll takes nothing returns nothing
        local integer listIndex = LoadInteger(Hash, GetHandleId(BlzGetTriggerFrame()), 0)
        local framehandle frame = TasButtonListSlider[listIndex]

        if GetLocalPlayer() == GetTriggerPlayer() then
            if BlzGetTriggerFrameValue() > 0 then
                call BlzFrameSetValue(frame, BlzFrameGetValue(frame) + TasButtonListStepSize[listIndex])
            else
                call BlzFrameSetValue(frame, BlzFrameGetValue(frame) - TasButtonListStepSize[listIndex])
            endif
        endif
        set frame = null
    endfunction

    // scrolling while pointing on slider aswell as calling
    function TasButtonListTriggerActionSlider takes nothing returns nothing
        local integer listIndex = LoadInteger(Hash, GetHandleId(BlzGetTriggerFrame()), 0)
        local integer filteredDataHash = GetHandleId(TasButtonListDataListFiltered[listIndex])
        local integer dataFilteredCount = LoadInteger(Hash, filteredDataHash, 0)
        local framehandle frame = BlzGetTriggerFrame()
        if GetLocalPlayer() == GetTriggerPlayer() then
            if BlzGetTriggerFrameEvent() == FRAMEEVENT_MOUSE_WHEEL then
                if BlzGetTriggerFrameValue() > 0 then
                    call BlzFrameSetValue(frame, BlzFrameGetValue(frame) + TasButtonListStepSize[listIndex])
                else
                    call BlzFrameSetValue(frame, BlzFrameGetValue(frame) - TasButtonListStepSize[listIndex])
                endif
            else
                // when there is enough data use viewPoint. the Viewpoint is reduced from the data to make top being top.
                if dataFilteredCount > TasButtonListButtonCount[listIndex] then
                    set TasButtonListViewPoint[listIndex] = dataFilteredCount - R2I(BlzGetTriggerFrameValue())
                else
                    set TasButtonListViewPoint[listIndex] = 0
                endif
                call UpdateTasButtonList(listIndex)
            endif
        endif
        set frame = null
    endfunction

    // runs once for each button shown
    function UpdateTasButtonListDefaultObject takes nothing returns nothing
    //TasButtonListFrame
    //TasButtonListData
    //TasButtonListIndex
        local integer frameHandle = GetHandleId(TasButtonListFrame)
        local integer data = TasButtonListData
        local integer lumber
        local integer gold
     
        call BlzFrameSetTexture(LoadFrameHandle(Hash, frameHandle, HASH_ICON),  BlzGetAbilityIcon(data), 0, false)
        call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TEXT), GetObjectName(data))

        call BlzFrameSetTexture(LoadFrameHandle(Hash, frameHandle, HASH_TOOL_TIP_ICON), BlzGetAbilityIcon(data), 0, false)
        call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TOOL_TIP_NAME), GetObjectName(data))
        call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TOOL_TIP_TEXT), BlzGetAbilityExtendedTooltip(data, 0))

        if not IsUnitIdType(data, UNIT_TYPE_HERO) then
            // GetUnitWoodCost GetUnitGoldCost CRASH with heroes
            set lumber = GetUnitWoodCost(data)
            set gold = GetUnitGoldCost(data)
            if GetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_GOLD) >= gold then
                call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TEXT_GOLD), I2S(GetUnitGoldCost(data)))
            else
                call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TEXT_GOLD), "|cffff2010" + I2S(GetUnitGoldCost(data)))
            endif
           
            if GetPlayerState(GetLocalPlayer(), PLAYER_STATE_RESOURCE_LUMBER) >= lumber then
               call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TEXT_LUMBER), I2S(GetUnitWoodCost(data)))
            else
               call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TEXT_LUMBER), "|cffff2010" + I2S(GetUnitWoodCost(data)))
            endif
        else
            call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TEXT_LUMBER), "0")
            call BlzFrameSetText(LoadFrameHandle(Hash, frameHandle, HASH_TEXT_GOLD), "0")
        endif
    endfunction

    function SearchTasButtonListDefaultObject takes nothing returns boolean
    //TasButtonListText
    //TasButtonListData
    //TasButtonListIndex
        return FindIndex(GetObjectName(TasButtonListData), TasButtonListText) >= 0
    endfunction

    function InitTasButtonListObject8c takes framehandle parent, code buttonAction, code rightClickAction, code updateAction, code searchAction, code filterAction, code asyncAction, code asyncRigthAction returns integer
        local framehandle frame
        local integer playerIndex = 0
        set Counter = Counter + 1
        // the locations are created to have an unique slot in the hash which are used as something like a Lua table.
        set TasButtonListDataList[Counter] = Location(0, 0) //
        // each player also got an own list
        loop
            call SaveLocationHandle(Hash, GetHandleId(TasButtonListDataList[Counter]), playerIndex, Location(0,0))
            set playerIndex = playerIndex + 1
            exitwhen playerIndex == bj_MAX_PLAYER_SLOTS
        endloop
        set TasButtonListDataListFiltered[Counter] = Location(0, 0) //
        set TasButtonListFrameList[Counter] = Location(0, 0) //
        set TasButtonListParent[Counter] = parent
        set TasButtonListViewPoint[Counter] = 0

        set TasButtonListButtonAction[Counter] = CreateTrigger() //call this inside the SyncAction after a button is clicked
        set TasButtonListUpdateAction[Counter] = CreateTrigger() //function defining how to display stuff (async)
        set TasButtonListFilterAction[Counter] = CreateTrigger() //function to return the searched Text (async)
        set TasButtonListSearchAction[Counter] = CreateTrigger()
        set TasButtonListRightAction[Counter] = CreateTrigger()
        set TasButtonListAsyncAction[Counter] = CreateTrigger()
        set TasButtonListAsyncRightAction[Counter] = CreateTrigger()
       
        call TriggerAddAction(TasButtonListButtonAction[Counter], buttonAction)
        if rightClickAction != null then
            call TriggerAddAction(TasButtonListRightAction[Counter], rightClickAction)
        endif
       
        // update is a condition with it can be run with TriggerEvaluate in localPlayer code. TriggerExecute would desync
        if updateAction == null then
            call TriggerAddCondition(TasButtonListUpdateAction[Counter], Filter(function UpdateTasButtonListDefaultObject))
        else
            call TriggerAddCondition(TasButtonListUpdateAction[Counter], Filter(updateAction))
        endif

        if searchAction == null then
            call TriggerAddCondition(TasButtonListSearchAction[Counter], Filter(function SearchTasButtonListDefaultObject))
        else
            call TriggerAddCondition(TasButtonListSearchAction[Counter], Filter(searchAction))
        endif
        if filterAction != null then
            call TriggerAddCondition(TasButtonListFilterAction[Counter], Filter(filterAction))
        endif

        if asyncAction != null then
            call TriggerAddCondition(TasButtonListAsyncAction[Counter], Filter(asyncAction))
        endif

        if asyncRigthAction != null then
            call TriggerAddCondition(TasButtonListAsyncRightAction[Counter], Filter(asyncRigthAction))
        endif
       
        set frame = BlzCreateFrameByType("SLIDER", "", parent, "", 0)
        set TasButtonListSyncFrame[Counter] = frame
        call BlzFrameSetMinMaxValue(frame, 0, 9999999)
        call BlzFrameSetStepSize(frame, 1.0)
        call BlzTriggerRegisterFrameEvent(SyncTrigger, frame, FRAMEEVENT_SLIDER_VALUE_CHANGED)
        call BlzFrameSetVisible(frame, false)
        call SaveInteger(Hash, GetHandleId(frame), 0, Counter)

        set frame = BlzCreateFrameByType("SLIDER", "", parent, "", 0)
        set TasButtonListSyncFrameRight[Counter] = frame
        call BlzFrameSetMinMaxValue(frame, 0, 9999999)
        call BlzFrameSetStepSize(frame, 1.0)
        call BlzTriggerRegisterFrameEvent(SyncRightTrigger, frame, FRAMEEVENT_SLIDER_VALUE_CHANGED)
        call BlzFrameSetVisible(frame, false)
        call SaveInteger(Hash, GetHandleId(frame), 0, Counter)

        set frame = BlzCreateFrame("TasEditBox", parent, 0, 0)
        set TasButtonListInputFrame[Counter] = frame
        call BlzTriggerRegisterFrameEvent(SearchTrigger, frame, FRAMEEVENT_EDITBOX_TEXT_CHANGED)
        call BlzFrameSetPoint(frame, FRAMEPOINT_TOPRIGHT, parent, FRAMEPOINT_TOPRIGHT, 0, 0)
        call SaveInteger(Hash, GetHandleId(frame), 0, Counter)

        set frame = null
        return Counter
    endfunction

    // this should have beend called InitTasButtonListObject8
    function InitTasButtonListObjectEx takes framehandle parent, code buttonAction, code rightClickAction, code updateAction, code searchAction, code filterAction returns integer
        return InitTasButtonListObject8c(parent, buttonAction, rightClickAction, updateAction, searchAction, filterAction, null, null)
    endfunction

    function InitTasButtonListObject takes framehandle parent, code buttonAction, code updateAction, code searchAction, code filterAction returns integer
        return InitTasButtonListObjectEx(parent, buttonAction, null, updateAction, searchAction, filterAction)
    endfunction

    function InitTasButtonListSlider takes integer listIndex, integer stepSize, integer rowCount returns nothing
        local framehandle frame = BlzCreateFrameByType("SLIDER", "FrameListSlider", TasButtonListParent[listIndex], "QuestMainListScrollBar", 0)
        local framehandle buttonFrame = LoadFrameHandle(Hash, GetHandleId(TasButtonListFrameList[listIndex]), 1)
        set TasButtonListSlider[listIndex] = frame
        call SaveInteger(Hash, GetHandleId(frame), 0, listIndex) // the slider nows the TasButtonListobject
        set TasButtonListStepSize[listIndex] = stepSize
       
        call BlzFrameSetStepSize(frame, stepSize)
        call BlzFrameClearAllPoints(frame)
        call BlzFrameSetVisible(frame, true)
        call BlzFrameSetMinMaxValue(frame, 0, 0)
        call BlzFrameSetPoint(frame, FRAMEPOINT_TOPLEFT, buttonFrame, FRAMEPOINT_TOPRIGHT, 0, 0)
        call BlzFrameSetSize(frame, 0.012, BlzFrameGetHeight(buttonFrame) * rowCount)
        call BlzTriggerRegisterFrameEvent(SliderTrigger, frame , FRAMEEVENT_SLIDER_VALUE_CHANGED)
        call BlzTriggerRegisterFrameEvent(SliderTrigger, frame , FRAMEEVENT_MOUSE_WHEEL)
    endfunction

    //Demo Creators
    function CreateTasButtonTooltip takes integer frameHandle, framehandle frameButton, framehandle parent returns nothing
        local framehandle frame = BlzCreateFrame("TasButtonListTooltipBox", frameButton, 0, 0)
        local framehandle frameText = BlzGetFrameByName("TasButtonListTooltipText", 0)
        call SaveFrameHandle(Hash, frameHandle, HASH_TOOL_TIP, frame)
        call SaveFrameHandle(Hash, frameHandle, HASH_TOOL_TIP_ICON, BlzGetFrameByName("TasButtonListTooltipIcon", 0))
        call SaveFrameHandle(Hash, frameHandle, HASH_TOOL_TIP_NAME, BlzGetFrameByName("TasButtonListTooltipName", 0))
        call SaveFrameHandle(Hash, frameHandle, HASH_TOOL_TIP_SEP, BlzGetFrameByName("TasButtonListTooltipSeperator", 0))
        call SaveFrameHandle(Hash, frameHandle, HASH_TOOL_TIP_TEXT, frameText)

        call BlzFrameSetTooltip(frameButton, frame)

        call BlzFrameSetPoint(frameText, FRAMEPOINT_TOPRIGHT, parent, FRAMEPOINT_TOPLEFT, -0.001, -0.052)
        call BlzFrameSetPoint(frame, FRAMEPOINT_TOPLEFT, BlzGetFrameByName("TasButtonListTooltipIcon", 0), FRAMEPOINT_TOPLEFT, -0.005, 0.005)
        call BlzFrameSetPoint(frame, FRAMEPOINT_BOTTOMRIGHT, frameText, FRAMEPOINT_BOTTOMRIGHT, 0.005, -0.005)
    endfunction

    function CreateTasButtonList10 takes string buttonName, integer cols, integer rows, framehandle parent, code buttonAction, code rightClickAction, code updateAction, code searchAction, code filterAction, code asyncAction, code asyncRigthAction, real colGap, real rowGap returns integer
        local integer buttonCount = rows*cols
        local integer listIndex = InitTasButtonListObject8c(parent, buttonAction, rightClickAction, updateAction, searchAction, filterAction, asyncAction, asyncRigthAction)
        local integer i = 1
        local integer frameListHash = GetHandleId(TasButtonListFrameList[listIndex])
        local framehandle frame
        local framehandle frameButton
        local integer frameHandle

        local integer rowRemain = cols
        set TasButtonListButtonCount[listIndex] = buttonCount
        loop
            exitwhen i > buttonCount
           
            set frame = BlzCreateFrame(buttonName, parent, 0, 0)
            set frameHandle = GetHandleId(frame)
            if frameHandle == 0 then
                call BJDebugMsg("TasButtonList - Error - can't create Button:" + buttonName)
            endif
            call SaveFrameHandle(Hash, frameListHash, i, frame)
            call SaveInteger(Hash, frameHandle, 0, listIndex) // the button knows the TasButtonListIndex
            call SaveInteger(Hash, frameHandle, 1, i) // the button knows its index in the frameList
            call BlzTriggerRegisterFrameEvent(ButtonTrigger, frame, FRAMEEVENT_CONTROL_CLICK)
            call BlzTriggerRegisterFrameEvent(ButtonRightTrigger, frame, FRAMEEVENT_MOUSE_UP)
            call BlzTriggerRegisterFrameEvent(ButtonScrollTrigger, frame, FRAMEEVENT_MOUSE_WHEEL)
            set frameButton = frame

            call SaveFrameHandle(Hash, frameHandle, HASH_ICON, BlzGetFrameByName("TasButtonIcon", 0))
            call SaveFrameHandle(Hash, frameHandle, HASH_TEXT, BlzGetFrameByName("TasButtonText", 0))
            call SaveFrameHandle(Hash, frameHandle, HASH_ICON_GOLD, BlzGetFrameByName("TasButtonIconGold", 0))
            call SaveFrameHandle(Hash, frameHandle, HASH_TEXT_GOLD, BlzGetFrameByName("TasButtonTextGold", 0))
            call SaveFrameHandle(Hash, frameHandle, HASH_ICON_LUMBER, BlzGetFrameByName("TasButtonIconLumber", 0))
            call SaveFrameHandle(Hash, frameHandle, HASH_TEXT_LUMBER, BlzGetFrameByName("TasButtonTextLumber", 0))

            call CreateTasButtonTooltip(frameHandle, frameButton, parent)

            if i > 1 then
                if rowRemain == 0 then
                    call BlzFrameSetPoint(frameButton, FRAMEPOINT_TOP, LoadFrameHandle(Hash, frameListHash, i - cols), FRAMEPOINT_BOTTOM, 0, -rowGap)
                    set rowRemain = cols
                else
                    call BlzFrameSetPoint(frameButton, FRAMEPOINT_RIGHT, LoadFrameHandle(Hash, frameListHash, i - 1), FRAMEPOINT_LEFT, -colGap, 0)
                endif
            else
                call BlzFrameSetPoint(frameButton, FRAMEPOINT_TOPRIGHT, TasButtonListInputFrame[listIndex], FRAMEPOINT_BOTTOMRIGHT, 0, 0)
            endif
            set rowRemain = rowRemain - 1


            set i = i + 1
        endloop
        call InitTasButtonListSlider(listIndex, cols, rows)
        set frame = null
        set frameButton = null
        return listIndex
    endfunction

    function CreateTasButtonList8c takes string buttonName, integer cols, integer rows, framehandle parent, code buttonAction, code rightClickAction, code updateAction, code searchAction, code filterAction, code asyncAction, code asyncRigthAction returns integer
        return CreateTasButtonList10(buttonName, cols, rows, parent, buttonAction, rightClickAction, updateAction, searchAction, filterAction, asyncAction, asyncRigthAction, TasButtonListGapCol, TasButtonListGapRow)
    endfunction


    function CreateTasButtonListEx takes string buttonName, integer cols, integer rows, framehandle parent, code buttonAction, code rightClickAction, code updateAction, code searchAction, code filterAction returns integer
        return CreateTasButtonList8c(buttonName, cols, rows, parent, buttonAction, rightClickAction, updateAction, searchAction, filterAction, null, null)
    endfunction

    function CreateTasButtonList takes integer buttonCount, framehandle parent, code buttonAction, code updateAction, code searchAction, code filterAction returns integer
        return CreateTasButtonListEx("TasButton", 1, buttonCount, parent, buttonAction, null, updateAction, searchAction, filterAction)
    endfunction

    function CreateTasButtonListV2 takes integer rowCount, framehandle parent, code buttonAction, code updateAction, code searchAction, code filterAction returns integer
        return CreateTasButtonListEx("TasButtonSmall", 2, rowCount, parent, buttonAction, null, updateAction, searchAction, filterAction)
    endfunction

    function CreateTasButtonListV3 takes integer rowCount, framehandle parent, code buttonAction, code updateAction, code searchAction, code filterAction returns integer
        return CreateTasButtonListEx("TasButtonGrid", 3, rowCount, parent, buttonAction, null, updateAction, searchAction, filterAction)
    endfunction

    function TasButtonListAddDataEx takes integer listIndex, integer data, integer playerIndex returns nothing
        local integer listHandle = GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), playerIndex))
        local integer index = LoadInteger(Hash, listHandle, 0) + 1
        call SaveInteger(Hash, listHandle, 0, index)
        call SaveInteger(Hash, listHandle, index, data)
        if GetLocalPlayer() == Player(playerIndex) then
            // add to current filtered for local player only
            set listHandle = GetHandleId(TasButtonListDataListFiltered[listIndex])
            call SaveInteger(Hash, listHandle, 0, index)
            call SaveInteger(Hash, listHandle, index, index)
            call BlzFrameSetMinMaxValue(TasButtonListSlider[listIndex], TasButtonListButtonCount[listIndex], index)
        endif
    endfunction

    function TasButtonListAddData takes integer listIndex, integer data returns nothing
        local integer playerIndex = 0
        loop
            call TasButtonListAddDataEx(listIndex, data, playerIndex)
            set playerIndex = playerIndex + 1
            exitwhen playerIndex == bj_MAX_PLAYER_SLOTS
        endloop
    endfunction

    function TasButtonListCopyDataEx takes integer writeObject, integer readObject, integer playerIndex returns nothing
        local integer i = LoadInteger(Hash, GetHandleId(TasButtonListDataListFiltered[readObject]), 0)
        local integer listHandleRead = GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[readObject]), playerIndex))
        local integer listHandleWrite = GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[writeObject]), playerIndex))
        call FlushChildHashtable(Hash, listHandleWrite)
        call RemoveLocation(TasButtonListDataList[writeObject])

        loop
            exitwhen i < 0
            call SaveInteger(Hash, listHandleWrite, i, LoadInteger(Hash, listHandleRead, i))
            set i = i -1
        endloop
        if GetLocalPlayer() == Player(playerIndex) then
            call BlzFrameSetMinMaxValue(TasButtonListSlider[writeObject], TasButtonListButtonCount[writeObject], LoadInteger(Hash, listHandleRead, 0))
            call UpdateTasButtonList(writeObject)
        endif
    endfunction

    function TasButtonListCopyData takes integer writeObject, integer readObject returns nothing
        local integer playerIndex = 0
        loop
            call TasButtonListCopyDataEx(writeObject, readObject, playerIndex)
            set playerIndex = playerIndex + 1
            exitwhen playerIndex == bj_MAX_PLAYER_SLOTS
        endloop
    endfunction

    function TasButtonListRemoveDataEx takes integer listIndex, integer data, integer playerIndex returns nothing
        local integer listHandle = GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), playerIndex))
        local integer i = LoadInteger(Hash, listHandle, 0)
        local integer max = LoadInteger(Hash, listHandle, 0)
        local integer temp
        loop
            exitwhen i <= 0
            if LoadInteger(Hash, listHandle, 0) == data then
                call SaveInteger(Hash, listHandle, i, LoadInteger(Hash, listHandle, max))
                call SaveInteger(Hash, listHandle, 0, max - 1)
                call RemoveSavedInteger(Hash, listHandle, max)
                exitwhen true
            endif
            set i = i - 1
        endloop
        if GetLocalPlayer() == Player(playerIndex) then
            call BlzFrameSetMinMaxValue(TasButtonListSlider[listIndex], TasButtonListButtonCount[listIndex], LoadInteger(Hash, listHandle, 0))
        endif
    endfunction

    function TasButtonListRemoveData takes integer listIndex, integer data returns nothing
        local integer playerIndex = 0
        loop
            call TasButtonListRemoveDataEx(listIndex, data, playerIndex)
            set playerIndex = playerIndex + 1
            exitwhen playerIndex == bj_MAX_PLAYER_SLOTS
        endloop
    endfunction

    function TasButtonListClearDataEx takes integer listIndex, integer playerIndex returns nothing
        call FlushChildHashtable(Hash, GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), playerIndex)))
        if GetLocalPlayer() == Player(playerIndex) then
            call FlushChildHashtable(Hash, GetHandleId(TasButtonListDataListFiltered[listIndex]))
            call BlzFrameSetMinMaxValue(TasButtonListSlider[listIndex], 0, 0)
        endif    
    endfunction

    function TasButtonListClearData takes integer listIndex returns nothing
        local integer playerIndex = 0
        loop
            call TasButtonListClearDataEx(listIndex, playerIndex)
            set playerIndex = playerIndex + 1
            exitwhen playerIndex == bj_MAX_PLAYER_SLOTS
        endloop
    endfunction

        private function SyncRightTriggerAction takes nothing returns nothing  
            local integer listIndex = LoadInteger(Hash, GetHandleId(BlzGetTriggerFrame()), 0)
            local integer dataIndex = R2I(BlzGetTriggerFrameValue() + 0.5)
            set TasButtonListData = LoadInteger(Hash, GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), GetPlayerId(GetTriggerPlayer()))), dataIndex)
            set TasButtonListIndex = listIndex
            call TriggerExecute(TasButtonListRightAction[listIndex])

            call UpdateTasButtonList(listIndex)
        endfunction
        private function ButtonRightClickTriggerAction takes nothing returns nothing
        local framehandle frame = BlzGetTriggerFrame()
        local integer buttonIndex = LoadInteger(Hash, GetHandleId(frame), 1)
        local integer listIndex = LoadInteger(Hash, GetHandleId(frame), 0)
        local integer dataIndex = LoadInteger(Hash, GetHandleId(TasButtonListDataListFiltered[listIndex]), buttonIndex + TasButtonListViewPoint[listIndex])
        local integer data = LoadInteger(Hash, GetHandleId(LoadLocationHandle(Hash, GetHandleId(TasButtonListDataList[listIndex]), GetPlayerId(GetTriggerPlayer()))), dataIndex)

        set TasButtonListData = data
        set TasButtonListIndex = listIndex
        set TasButtonListFrame = frame

            if IsRightClick(GetTriggerPlayer()) and GetLocalPlayer() == GetTriggerPlayer() then            
                call TriggerEvaluate(TasButtonListAsyncRightAction[listIndex])
                call StartSound(RightClickSound)
                call BlzFrameSetValue(TasButtonListSyncFrameRight[listIndex], dataIndex)
            endif
        endfunction

     private function LoadToc takes nothing returns nothing    
        call BlzLoadTOCFile("war3mapimported\\TasButtonList.toc")  
     endfunction
     private function Init takes nothing returns nothing    
        local integer loopA = 0
       
        call LoadToc()
        call TriggerAddAction(SyncTrigger, function TasButtonListTriggerActionSync)
        call TriggerAddAction(ButtonTrigger, function TasButtonListTriggerActionButton)
        call TriggerAddAction(SearchTrigger, function TasButtonListTriggerActionSearch)
        call TriggerAddAction(ButtonScrollTrigger, function TasButtonListTriggerActionButtonScroll)
        call TriggerAddAction(SliderTrigger, function TasButtonListTriggerActionSlider)
        call TriggerAddAction(SyncRightTrigger, function SyncRightTriggerAction)
        call TriggerAddAction(ButtonRightTrigger, function ButtonRightClickTriggerAction)

        set RightClickSound = CreateSound("Sound\\Interface\\MouseClick1.wav", false, false, false, 10, 10, "")
        call SetSoundParamsFromLabel(RightClickSound, "InterfaceClick")
        call SetSoundDuration(RightClickSound, 239)

    endfunction

    endlibrary


There are some differences between the (v)jass & Lua version.
in the jass version the mapper's actions are run over triggers, hence there are globals instead of args.
"" """""" The Button is the frameObject instead of being a member of it.
""""" every TasButtonList is one Index in an array.
""""" data used in TasButtonList is only integer.
"""" accessing the Frames is ugly.​

Changelog


V10a (jass)
Rightclick was not aware of the the new Player based Data​
V10
One can now add additional space between cols & rows. (jass) (old api calls can use this without changing their api by globals: TasButtonListGapCol & TasButtonListGapRow)
Changed the used textures for the Buttons. The bordertexture were broken (Reforged and 1.31), in a more closer look.
V9a
(Lua) TasButtonListClearData cleared the FilterData List for all players.​
V9
seperated&Changed the rightclick detection from the system.
added optional AsyncButtonAction and AsyncRightClickAction. They are called directly inside the Click-Events for the clicking Player only.
Each Player can now have it's own Data in one TasButtonList.
Some fixes.
TasButtons change color while they are pushed.​

V8
A ButtonList can now have a RightClick Action
Improved the Included Demo Creators​
V7c Lua only
default-search ignores char case
creates Triggers&Actions pre map init by hooking into InitBlizzard​
V7B - Fix
Changed demo Map Code to stop desync in the Lua version.​
V7B
some optimiziation in Lua version
New Fdf
Removed the unique name Part of children of TasButtonXxx
The Tooltip Box will extend/shrink to fit the shown Text (Extended Tooltip).
Pushed the TasButtonList Creators to the bottom of the Lua code (they are not so much tied to the system itself more an example of usage)
V7A
Slider's top position is now the data's top position​
V7
One can now force a list to search & filter
The Slider should now only show when there is more data than buttons​
V6
replaced BlzSendSyncData with a SLIDER
removed some wrong arguments or when they were to much mostly GetObjectName and BlzFrameCreateByType.
Added a (v)jass version​
V5 First Release
Previews
Contents

TasButtonListV10 (Map)

TasButtonListV10a jass (Map)

Reviews
MyPad
This can be very useful for mappers. Approved
  1. Kain88

    Kain88

    Joined:
    May 26, 2020
    Messages:
    5
    Resources:
    0
    Resources:
    0
    Come on GUI or Jass version=)
     
  2. imek

    imek

    Joined:
    Aug 18, 2016
    Messages:
    42
    Resources:
    0
    Resources:
    0
    Brilliant! Super helpful. I got it to work too! Thank you Tasyen! Now I just need to study it and learn how you made it.
     
  3. imek

    imek

    Joined:
    Aug 18, 2016
    Messages:
    42
    Resources:
    0
    Resources:
    0
    Question: how to i get the Button List to close out and then Open a different Button List depending on which button I click on?

    Example:

    TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\PASHolyNovaHD.dds", Text = "Wizard"})
    TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNSlow", Text = "Custom B"})
    TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNInvisibility", Text = "Custom C"})
    TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNBanish", Text = "Custom D"})
    TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNCrystalBall", Text = "Custom E"})
    TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNBoots", Text = "Custom F"})
    TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNTalisman", Text = "Custom G"})

    If I click on the Wizard button I want to go to the Units under that category.
     
  4. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,735
    Resources:
    37
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    20
    JASS:
    1
    Resources:
    37
    To show hide a TasButtonList one uses BlzFrameSetVisible onto the ButtonLists Parent, at least it is meant to be handled that way. The buttonslist knows their parent: can be done like that
    BlzFrameSetVisible(buttonListObject.Parent, false)


    Now you have to set the buttonAction as wanted when creating the ButtonList:
    inside the buttonAction somehow know that the wanted Button showing that data is clicked, here I check for data.Text == "Wizard" then show/hide the parents of the buttonsLists for the triggering player only.
    Code (Lua):

    local object = CreateTasButtonList(4, frame, function(data, buttonListObject, dataIndex)
            if data.Text == "Wizard" and GetTriggerPlayer() == GetLocalPlayer() then
                BlzFrameSetVisible(buttonListObject.Parent, false)
                BlzFrameSetVisible(otherButtonList.Parent, true)
            end
        end)
     
    This example will shows only the concept of showing hiding, might be easier to understand than the now longer example below:

    Code (Lua):
    do
        local real = MarkGameStarted
        function MarkGameStarted()
            real()
        xpcall(function()
        -- create an empty Frame that will be the ButtonLists parent. if you want to hide/move the ButtonList hide/move the parent.
        local frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0,0)
        BlzFrameSetSize(frame, 0.23, 0.001)
        BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOP, 0.6, 0.5)
        -- create a new ButtonList with 4 Rows, frame is the parent and define the action when clicking the Button
        local object = CreateTasButtonList(3, frame, function(data, buttonListObject, dataIndex)
            if data.Text == "Wizard" and GetTriggerPlayer() == GetLocalPlayer() then
                BlzFrameSetVisible(buttonListObject.Parent, false)
                BlzFrameSetVisible(WizardButtonList.Parent, true)
            end
        end,
        function(frameObject, data)
            BlzFrameSetTexture(frameObject.Icon, data.Icon, 0, false)
            BlzFrameSetText(frameObject.Text, data.Text)

            BlzFrameSetTexture(frameObject.ToolTipFrameIcon, data.Icon, 0, false)
            BlzFrameSetText(frameObject.ToolTipFrameName, data.Text)
        end)
        -- add various data
        TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNPriest", Text = "Wizard"})
        TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNSlow", Text = "Custom B"})
        TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNInvisibility", Text = "Custom C"})

        MainList = object
        UpdateTasButtonList(object)
     
        local frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0,0)
        BlzFrameSetSize(frame, 0.23, 0.001)
        BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOP, 0.6, 0.5)
        BlzFrameSetVisible(frame, false)
        -- create a new ButtonList with 4 Rows, frame is the parent and define the action when clicking the Button
        local object = CreateTasButtonList(2, frame, function(data, buttonListObject, dataIndex)
            if data.Text == "Back" and GetTriggerPlayer() == GetLocalPlayer() then
                BlzFrameSetVisible(buttonListObject.Parent, false)
                BlzFrameSetVisible(MainList.Parent, true)
            elseif  data.Text == "Close" and GetTriggerPlayer() == GetLocalPlayer() then
                BlzFrameSetVisible(buttonListObject.Parent, false)
            end
        end,
        function(frameObject, data)
            BlzFrameSetTexture(frameObject.Icon, data.Icon, 0, false)
            BlzFrameSetText(frameObject.Text, data.Text)

            BlzFrameSetTexture(frameObject.ToolTipFrameIcon, data.Icon, 0, false)
            BlzFrameSetText(frameObject.ToolTipFrameName, data.Text)
        end)
        WizardButtonList = object
        TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNTalisman", Text = "Back"})
        TasButtonListAddData(object, {Icon = "ReplaceableTextures\\CommandButtons\\BTNTalisman", Text = "Close"})

        -- force an update
        UpdateTasButtonList(object)

        print("done")
    end, print)
    end
    end
    Good that this system is useful to you.

    Edited: Replaced selfexecution with a less problematic approach
     
    Last edited: Sep 22, 2020
  5. imek

    imek

    Joined:
    Aug 18, 2016
    Messages:
    42
    Resources:
    0
    Resources:
    0
    Thank you again.
     
  6. imek

    imek

    Joined:
    Aug 18, 2016
    Messages:
    42
    Resources:
    0
    Resources:
    0
    I am still having trouble creating categories. I think I almost have all the code I need, but there is still stuff I don't understand. I am attaching my map file to this post. Maybe if you look at what I'm trying to do you will be able to give me instructions. I was able to make the 1st category but not all the others. Imek Amtgard map 05-31-2020 | HIVE

    Question: Can you please tell me how to finish adding the categories to my map? I need 13 different categories for different units. The 1st category has Goose and Fox in it.
     
  7. SpasMaster

    SpasMaster

    Joined:
    Jan 29, 2010
    Messages:
    1,893
    Resources:
    4
    Icons:
    2
    Maps:
    2
    Resources:
    4
    I am curious if a Jass version is something you plan on doing?

    Regardless, this seems neat as usual. +rep
     
  8. imek

    imek

    Joined:
    Aug 18, 2016
    Messages:
    42
    Resources:
    0
    Resources:
    0
    Never mind I figured out how to it works. I added all the categories. Thank you again Tasyen!
     
  9. imek

    imek

    Joined:
    Aug 18, 2016
    Messages:
    42
    Resources:
    0
    Resources:
    0
    So I have this code below and I need to UpdateTasButtonList(object) for the --add various data section of the code. But I can't get the icon with the value H001 to update and show up in the menu. Can some one please help me do this?

    --******SUMMON UNITS For WIZARD CLASS****************************************************************
    local frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0,0)
    BlzFrameSetSize(frame, 0.23, 0.001)
    BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOP, 0.4, 0.5)
    BlzFrameSetVisible(frame, false)

    -- create a new ButtonList with 10 Rows, frame is the parent and define the action when clicking the Button
    local object = CreateTasButtonList(10, frame, function(data, buttonListObject, dataIndex)
    if data.Text == "Back" and GetTriggerPlayer() == GetLocalPlayer() then
    BlzFrameSetVisible(buttonListObject.Parent, false)
    BlzFrameSetVisible(MainList.Parent, true)
    elseif data.Text == "Close" and GetTriggerPlayer() == GetLocalPlayer() then
    BlzFrameSetVisible(buttonListObject.Parent, false)
    end

    if data.Text == "Atta" and GetTriggerPlayer() == GetLocalPlayer() then
    BlzFrameSetVisible(buttonListObject.Parent, false)
    local frame = BlzCreateFrameByType("FRAME", "", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0), 0,0)
    BlzFrameSetSize(frame, 0.23, 0.001)
    BlzFrameSetAbsPoint(frame, FRAMEPOINT_TOP, 0.4, 0.5)
    -- create a new ButtonList with 1 Rows, frame is the parent and define the action when clicking the Button
    local object = CreateTasButtonList(1, frame, function(data, buttonListObject, dataIndex)
    -- create an unit for the clicking player at 0/0 with facing 0
    CreateUnit(GetTriggerPlayer(), data, 0, 0, 0)
    BlzFrameSetVisible(buttonListObject.Parent, false)
    end)

    -- add various data
    TasButtonListAddData(object, FourCC("H001"))

    end
     
  10. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,735
    Resources:
    37
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    20
    JASS:
    1
    Resources:
    37
    I was expecting this, hence I already have thinkered about a way to create this in (v)jass. I am not against it. Probably do it in some time, but don't expect great (v)jass.
     
    Last edited: Jun 1, 2020
  11. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,735
    Resources:
    37
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    20
    JASS:
    1
    Resources:
    37
    Updated to Version6 which includes some small changes/fixes aswell as a (v)jass version.

    The (v)jass versions was built out of the Lua version hence it is also quite similar.
    There are still some differences between the (v)jass & Lua version.
    in the jass version the mapper's actions are run over triggers, hence there are globals instead of args.
    "" """""" The Button is the frameObject instead of being a member of it.
    """"" every TasButtonList is one Index in an array.
    """"" data used in TasButtonList is only integer.
    """" accessing the Frames is ugly.​
    Code (vJASS):

        //args for custom user actions
        integer TasButtonListData = 0
        string TasButtonListText = ""
        boolean TasButtonListIsSearching = false
        integer TasButtonListIndex = 0
        framehandle TasButtonListFrame = null
     


    The (v)jass versions did desync at first when i was using TriggerAction + TriggerExecute for the updateAction. In the released version this was replaced with TriggerCondition + TriggerEvaluate. With this change there were no desyncs during testing in Warcraft 3 1.31.1.
     
    Last edited: Jun 3, 2020
  12. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,735
    Resources:
    37
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    20
    JASS:
    1
    Resources:
    37
    Updated to V7 a small update.
    the searchTriggerAction code was pushed into a call able function, making it more easy/faster to reapply filter/search.
    The scrollFrame is now only shown when there is more filtered Data then buttons (it was also shown with an equal amount).
     
    Last edited: Jun 16, 2020
  13. KitsuneTailsPrower

    KitsuneTailsPrower

    Joined:
    Oct 9, 2019
    Messages:
    20
    Resources:
    0
    Resources:
    0
    A very useful and flexible system
     
  14. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,572
    Resources:
    9
    Models:
    1
    Icons:
    2
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    9
    Splendid work with creating UI systems. There is a minor kink, though.
    Apparently, the button elements (when the slider is at the top) are supposed to be at the bottom.
    The video below should better explain the issue:

     
  15. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,735
    Resources:
    37
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    20
    JASS:
    1
    Resources:
    37
    Well, I don't get the problem.
     
  16. MyPad

    MyPad

    Spell Reviewer

    Joined:
    May 9, 2014
    Messages:
    1,572
    Resources:
    9
    Models:
    1
    Icons:
    2
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    9
    upload_2020-8-10_17-7-18.png
    upload_2020-8-10_17-7-42.png
    upload_2020-8-10_17-8-10.png
    upload_2020-8-10_17-8-24.png

    Visually speaking, the list of items displayed when the slider is at the top should be A-B-C-D. Instead, the slider is at the bottom. Likewise, when displaying D-E-F-G, the slider should be at the bottom, but is situated at the top.

    This was tested on the lua version of the map, with a slight positional modification to accommodate for the pictures.
     
  17. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,735
    Resources:
    37
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    20
    JASS:
    1
    Resources:
    37
    Okay, got it. That is indeed confusing and should be changed.
     
  18. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,735
    Resources:
    37
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    20
    JASS:
    1
    Resources:
    37
    Updated to 7a:
    The value of the slider is now subtracted from the max. Therefore the slider top position is now the top data position.

    But now one has to set the slider position to the maxium after having filled it with data to prevent a glitch. This replaces the update Line which one had to do.
     
  19. Tasyen

    Tasyen

    Joined:
    Jul 18, 2010
    Messages:
    1,735
    Resources:
    37
    Tools:
    2
    Maps:
    3
    Spells:
    11
    Tutorials:
    20
    JASS:
    1
    Resources:
    37
    Updated to 7B:
    The built in Tooltip-Box will now resize itself, based on the amount of text inside the Extended Tooltip (the bottom part).
    7B uses a different fdf then previous versions, if you update you have to import the new one. From this version the fdf has in the first line a comment for which version it was created.
    Made some parts of the Lua version faster.
    Uploaded new Images to show that.
     
    Last edited: Sep 2, 2020