• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • ✅ The POLL for Hive's Texturing Contest #33 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!

TasUIContainers

Introduction


This is a pack of systems created for Warcraft 3 V1.31.1 or higher in Lua mode that can be used for custom UI-Frame making. Most of the systems are about frame Hierachy and Layout which when used can make positing easier. The systems in this pack were made for for not-SimpleFrames.

Contains
TasFrameList
TasFrameFlow
TasWindow
TasWindowTab
TasSliderControl

TasFrameList


TasFrameList displays managed frames in a col that can be scrolled by the user.
The Frames added need to have a Size. TasFrameList manages Visibility, position and parentship for this Frames. At least one managed Frame is displayed, further Frames are only displayed when they fit into the remaining Height of TasFrameList. By scrolling the current first displayed Frame is changed and TasFrameList updates its content's position and visibility.
282125-a9d7fdaa1b177beadbb1759c6ce91067.jpg

You can have "multiple" Frames in one row by combining them into a parent Frame and then add that parent Frame to TasFrameList. The Frames in this case need to be placed relative inside the parent's size. Thats how this pack of 3 in one row are done in the image.
282133-46e19088cc89304ad5de5ecf0875b62e.png

Lua:
--[[
    TasFrameList Simple V1.2 by Tasyen
    A Frame that contains 1 Col of Frames, a fraction of the added Frames is displayed at once. The user can change the shown frames by scrolling a slider.
    FrameLists can also contain a TasFrameList.
    The displayed amount of Frames depends on the TasFrameList size, this Size only changes when changed with BlzFrameSetSize or better the special version added into this.

    TasFrameList Simple does not require a fdf
    can use TasFrameAction

    function TasFrameList.create([margin, parent, createContext, frame])
        creates a new TasFrameList
        no frame -> create a new frame for parent

    function TasFrameList.define([margin, frame, createContext])
        wrapper for .create(), make frame a TasFrameList

    function TasFrameList.setSize(frameListTable, xSize, ySize)
        a custom Width seter, it makes the slider more accurate without the slider can not be clicked correctly.

    function TasFrameList.add(frameListTable, frame)
        adds frame to as last element of frameListTable

    function TasFrameList.remove(frameListTable, frame, noUpdate)
        removes frame (can be a number) from frameListTable, skip noUpdate that is only used from TasFrameList.destory

    function TasFrameList.update(frameListTable)
        update the shown content, should be done automatic with user interaction
        calls frameListTable.Action(frameListTable)
--]]

TasFrameList = {}
FrameList = TasFrameList --backwards compatible
function TasFrameList.create(margin, parent, createContext, frame)
    local newObj = {}
    if not createContext then createContext = 0 end
    if not parent then parent = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0) end
    if not margin then margin = 0 end
    if not frame then newObj.Frame = BlzCreateFrameByType("SLIDER", "FrameListFrame", parent, "", createContext)
    else newObj.Frame = frame end
        
    newObj.Slider = BlzCreateFrameByType("SLIDER", "FrameListSlider", newObj.Frame, "QuestMainListScrollBar", createContext)
    newObj.Margin = margin

    BlzFrameSetStepSize(newObj.Slider, 1)
    BlzFrameClearAllPoints(newObj.Slider)
    BlzFrameSetVisible(newObj.Slider, true)
    BlzFrameSetMinMaxValue(newObj.Slider, 1, 1)
    
    BlzFrameSetPoint(newObj.Slider, FRAMEPOINT_TOPRIGHT, newObj.Frame, FRAMEPOINT_TOPRIGHT, 0, 0)
    local xSize, ySize= 0.012, 0.139
    if frame then xSize, ySize = BlzFrameGetWidth(frame),BlzFrameGetHeight(frame) end
    TasFrameList.setSize(newObj, xSize, ySize)

    newObj.Content = {}
    TasFrameList[newObj.Slider] = newObj
    TasFrameList[newObj.Frame] = newObj
    if TasSliderAction then -- have TasFraneAction?
        TasSliderAction(newObj.Slider, TasFrameList.TasSliderAction, 1)
        TasSliderAction(newObj.Frame, nil, 1, newObj.Slider)
    else
        if not TasFrameList.SliderTrigger then
            TasFrameList.SliderTrigger = CreateTrigger()
            TriggerAddAction(newObj.SliderTrigger, TasFrameList.SliderAction)
        end
        BlzTriggerRegisterFrameEvent(TasFrameList.SliderTrigger, newObj.Slider , FRAMEEVENT_SLIDER_VALUE_CHANGED)
        BlzTriggerRegisterFrameEvent(TasFrameList.SliderTrigger, newObj.Slider , FRAMEEVENT_MOUSE_WHEEL)
    end
    return newObj
end

function TasFrameList.define(margin, frame, createContext) return TasFrameList.create(margin, nil, createContext, frame) end

function TasFrameList.update(frameListTable)
    local sliderValue = R2I( BlzFrameGetValue(frameListTable.Slider))
    local sizeFrameList = BlzFrameGetHeight(frameListTable.Frame)
    local contentCount = #frameListTable.Content

    for index = 1, contentCount, 1 do
        local frame = frameListTable.Content[index]
        if index < sliderValue then
            --print("Hide Prev", index)
            BlzFrameSetVisible(frame, false)
        else
            local sizeFrame = BlzFrameGetHeight(frame)
            sizeFrameList = sizeFrameList - sizeFrame
            BlzFrameClearAllPoints(frame)  
            if index == sliderValue then                
                BlzFrameSetVisible(frame, true)
                BlzFrameSetPoint(frame, FRAMEPOINT_TOPRIGHT, frameListTable.Slider, FRAMEPOINT_TOPLEFT, 0, 0)
            else
                BlzFrameSetVisible(frame, sizeFrameList >= 0)
                BlzFrameSetPoint(frame, FRAMEPOINT_TOPRIGHT, frameListTable.Content[index - 1], FRAMEPOINT_BOTTOMRIGHT, 0, -frameListTable.Margin)
            end
        end
    end
    if frameListTable.Action then frameListTable.Action(frameListTable) end
end
TasFrameList.setContentPoints = TasFrameList.update

function TasFrameList.setSize(frameListTable, xSize, ySize)
    BlzFrameSetSize(frameListTable.Frame, xSize, ySize)
    BlzFrameSetSize(frameListTable.Slider, 0.012, ySize)
end

function TasFrameList.add(frameListTable, frame)
    table.insert(frameListTable.Content, frame)
    BlzFrameSetParent(frame, frameListTable.Frame) 
    BlzFrameSetMinMaxValue(frameListTable.Slider, 1, #frameListTable.Content)
    TasFrameList.update(frameListTable)
end

function TasFrameList.remove(frameListTable, frame, noUpdate)
    local removed = nil
    if not frameListTable or #frameListTable.Content == 0 then return false end
    if not frame then
        removed = table.remove(frameListTable.Content)
    elseif type(frame) == "number" then
        removed = table.remove( frameListTable.Content, frame)
    else
        for index, value in ipairs(frameListTable.Content)
        do
            if frame == value then
                removed = table.remove(frameListTable.Content, index)
                break
            end
        end
    end

    if removed then
        BlzFrameClearAllPoints(removed)
        BlzFrameSetVisible(removed, false)
        if not noUpdate then
            BlzFrameSetMinMaxValue(frameListTable.Slider, 1, #frameListTable.Content)
            BlzFrameSetValue(frameListTable.Slider, 1)
            TasFrameList.update(frameListTable)
        end
    end
    return #frameListTable.Content
end

function TasFrameList.SliderAction()
    local frame = BlzGetTriggerFrame()
    if GetLocalPlayer() == GetTriggerPlayer() then
        if BlzGetTriggerFrameEvent() == FRAMEEVENT_MOUSE_WHEEL then
            if BlzGetTriggerFrameValue() > 0 then
                BlzFrameSetValue(frame, BlzFrameGetValue(frame) + 1)
            else
                BlzFrameSetValue(frame, BlzFrameGetValue(frame) - 1)
            end
        end
        TasFrameList.update(TasFrameList[frame])
    end
end
function TasFrameList.TasSliderAction(frame, player, value)
    if GetLocalPlayer() == player then
        TasFrameList.update(TasFrameList[frame])
    end
end

TasFrameFlow


TasFrameFlow fills a Frame with Frames, in rows starting from TopLeft. To reveal later slots and hide earlier ones, the user can scroll it. TasFrameFlow can therefore hold more Frames than would fit inside of it.
TasFrameFlow takes control of parentship, position and visibility. A row's height is equal to the highest Frame within it. This requires frames to have a size. When desired, TasFrameFlow can include a slider.
282130-4e9ecf4c81c6acec3455b99215c6a3b1.jpg

Lua:
--[[
    TasFrameFlow V1.1 by Tasyen
    TasFrameFlow is a system that automatic fills a Frame from TopLeft with frames. Further frame try to be placed next to the previous one, if that fails TasFrameFlow starts a new row.
    This new added Frame is the previous for the next frame regardless if it started a new Row or not.
    The Frame using TasFrameFlow and the frames added need a size for this system to work.
    

    function TasFrameFlow.create(frame[, addSlider, marginX, marginY])
        creates a new TasFrameFlow for frame returns frameFlowTable.
        Having marginX space between 2 frames in 1 row and marginY space between 2 rows
        addSlider(true) creats a slider so the user can alter the frame shown at topLeft with that moves all Content.
        The slider will take over the size of the frame on creation, when the size changes you or was not right on that moment use TasFrameFlow.updateSlider.

    function TasFrameFlow.add(frameFlowTable, frame[, noUpdate])
        adds frame to the frameFlowTable. noUpdate (true) does not fit the new Frame into the Frame managed by TasFrameFlow.
        frame becomes a children of the Frame managed by frameFlowTable

    function TasFrameFlow.remove(frameFlowTable, [frame, noUpdate])
        removes frame (can be a number) from the frameFlowTable.
        calling this will also call TasFrameFlow.fit(frameFlowTable, 1).
        noUpdate (true) prevents calling TasFrameFlow.fit. Recommented when used multiple times in a row.
        returns true if the frameFlowTable still contains frames

    function TasFrameFlow.fit(frameFlowTable[, startingIndex])
        update the position and visibility of all content of frameFlowTable.
        starting with Content[startingIndex] at TopLeft.
        Frames with a lower index are hidden.
        no startingIndex is the same as 1.
        Use this function to scroll or after the size of the parentFrame or one of the content changed.
        This is also used after an TasFrameFlow
        calls frameFlowTable.Action(frameFlowTable)

    function TasFrameFlow.updateSlider(frameFlowTable)
        updates the Size of the slider to the current Size of the Frame managed by this frameFlowTable
--]]

TasFrameFlow = {}
FrameFlow = TasFrameFlow
-- creates a new TasFrameFlow filling frame
function TasFrameFlow.create(frame, addSlider, marginX, marginY)
    local frameFlowTable = {}
    frameFlowTable.Frame = frame --the frame filled
    frameFlowTable.Content = {} -- array of frames

    if addSlider then
        frameFlowTable.Slider = BlzCreateFrameByType("SLIDER", "FrameFlowSlider", frame, "QuestMainListScrollBar", 0)
    --  frameFlowTable.Slider = BlzCreateFrame("QuestMainListScrollBar", frame, "", 0)
        TasFrameFlow[frameFlowTable.Slider] = frameFlowTable
        BlzFrameClearAllPoints(frameFlowTable.Slider)
        BlzFrameSetStepSize(frameFlowTable.Slider, 1)
        BlzFrameSetSize(frameFlowTable.Slider, 0.012, BlzFrameGetHeight(frame))
        BlzFrameSetPoint(frameFlowTable.Slider, FRAMEPOINT_RIGHT, frame, FRAMEPOINT_RIGHT, 0, 0)
        BlzFrameSetVisible(frameFlowTable.Slider, true)
        BlzFrameSetMinMaxValue(frameFlowTable.Slider, 1, 1)
        TasSliderAction(frameFlowTable.Slider, TasFrameFlow.SliderAction)
    end
    if not marginX then marginX = 0 end
    frameFlowTable.MarginX = marginX --space between 2 frames in one row
    if not marginY then marginY = 0 end
    frameFlowTable.MarginY = marginY --additional space between 2 rows
    return frameFlowTable
end

function TasFrameFlow.calc(frameFlowTable, frame, prevFrame)
    local rowSizeX = frameFlowTable.CurrentRowRemainX
    local rowSizeY = frameFlowTable.CurrentRowSizeY
    local offsetY = frameFlowTable.CurrentOffsetY
    local parentframeSizeX = BlzFrameGetWidth(frameFlowTable.Frame)
    if frameFlowTable.Slider then --if there is an Slider reduce the used Space
        parentframeSizeX = parentframeSizeX - BlzFrameGetWidth(frameFlowTable.Slider)
    end
    local parentframeSizeY = BlzFrameGetHeight(frameFlowTable.Frame)
    rowSizeX = rowSizeX - BlzFrameGetWidth(frame) - frameFlowTable.MarginX
    BlzFrameClearAllPoints(frame)
    

    if rowSizeX >= 0 then
        BlzFrameSetPoint(frame, FRAMEPOINT_TOPLEFT, prevFrame, FRAMEPOINT_TOPRIGHT, frameFlowTable.MarginX, 0)
        rowSizeY = math.max( rowSizeY, BlzFrameGetHeight(frame))
    elseif rowSizeX < 0 then
        offsetY = offsetY + rowSizeY + frameFlowTable.MarginY
        rowSizeX = parentframeSizeX - BlzFrameGetWidth(frame)
        BlzFrameSetPoint(frame, FRAMEPOINT_TOPLEFT, frameFlowTable.Frame, FRAMEPOINT_TOPLEFT, 0, -offsetY)
        rowSizeY = BlzFrameGetHeight(frame)
    end
    BlzFrameSetVisible(frame, offsetY + BlzFrameGetHeight(frame) <= parentframeSizeY)
    prevFrame = frame

    --save this values to simple down adding 1 frame
    frameFlowTable.CurrentRowRemainX = rowSizeX
    frameFlowTable.CurrentRowSizeY = rowSizeY
    frameFlowTable.CurrentOffsetY = offsetY
end

--refits all frames, startingIndex is the index of frameFlowTable.Content being placed at TopLeft of the parent Frame
function TasFrameFlow.fit(frameFlowTable, startingIndex)
    if not frameFlowTable.Content or #frameFlowTable.Content == 0 then return end
    if not startingIndex then startingIndex = 1 end
    
    --hide frames before the starting Index
    for index = 1, startingIndex - 1, 1
    do
        BlzFrameSetVisible(frameFlowTable.Content[index], false)
    end
   
    local frame = frameFlowTable.Content[startingIndex]
    BlzFrameClearAllPoints(frame)
    BlzFrameSetVisible(frame, true)
    BlzFrameSetPoint(frame, FRAMEPOINT_TOPLEFT, frameFlowTable.Frame, FRAMEPOINT_TOPLEFT, 0, 0)
    
    local prevFrame = frame

    --reset values
    frameFlowTable.CurrentRowRemainX = BlzFrameGetWidth(frameFlowTable.Frame) - BlzFrameGetWidth(frame)
    if frameFlowTable.Slider then --if there is an Slider reduce the used Space
        frameFlowTable.CurrentRowRemainX = frameFlowTable.CurrentRowRemainX - BlzFrameGetWidth(frameFlowTable.Slider)
    end
    frameFlowTable.CurrentRowSizeY = BlzFrameGetHeight(frame)
    frameFlowTable.CurrentOffsetY = 0

    for index = startingIndex + 1, #frameFlowTable.Content, 1
    do
        local frame = frameFlowTable.Content[index]
        TasFrameFlow.calc(frameFlowTable, frame, prevFrame)
        
        prevFrame = frame
    end
    if frameFlowTable.Action then frameFlowTable.Action(frameFlowTable) end
end

--fit in a new frame at the end of the table
function TasFrameFlow.fitNewFrame(frameFlowTable, frame)
    TasFrameFlow.calc(frameFlowTable, frame, frameFlowTable.Content[#frameFlowTable.Content - 1])
end

function TasFrameFlow.remove(frameFlowTable, frame, noUpdate)
    local removed = nil
    if not frameFlowTable or #frameFlowTable.Content == 0 then return false end
    if not frame then
        removed = table.remove(frameFlowTable.Content)
    elseif type(frame) == "number" then
        removed = table.remove( frameFlowTable.Content, frame)
    else
        for index, value in ipairs(frameFlowTable.Content)
        do
            if frame == value then
                removed = table.remove(frameFlowTable.Content, index)
                break
            end
        end
    end
    if removed then
        BlzFrameClearAllPoints(removed)
        BlzFrameSetVisible(removed, false)
        BlzFrameSetMinMaxValue(frameFlowTable.Slider, 1, #frameFlowTable.Content)
        if not noUpdate then
            TasFrameFlow.fit(frameFlowTable, 1)
        end
    end
    return #frameFlowTable.Content
end


function TasFrameFlow.add(frameFlowTable, frame, noUpdate)
    table.insert(frameFlowTable.Content, frame)
    BlzFrameSetParent(frame, frameFlowTable.Frame)
    BlzFrameSetMinMaxValue(frameFlowTable.Slider, 1, #frameFlowTable.Content)
    if not noUpdate then
        if #frameFlowTable.Content == 1 then
            TasFrameFlow.fit(frameFlowTable, 1)
        else
            TasFrameFlow.fitNewFrame(frameFlowTable, frame)
        end
    end
end

function TasFrameFlow.updateSlider(frameFlowTable)
    if frameFlowTable.Slider then
        BlzFrameSetSize(frameFlowTable.Slider, 0.012, BlzFrameGetHeight(frameFlowTable.Frame))
    end
end

function TasFrameFlow.SliderAction(frame, player, value)
    if GetLocalPlayer() == player then
        TasFrameFlow.fit(TasFrameFlow[frame],  value)
    end
end

TasWindow


TasWindow is a set of Frames that allows the user to close/colapse it, one would use TasWindow to have something like multiboard but with any content you want.
A TasWindow is a Head & a Content Pane. The Head is a Text Title and a close/colapse Button. While the Content Pane is a Frame into which your custom frames go, it is right below the Head.
To use this correctly you use the Content Pane as parent of your Frames and place yours relative to it. The ContentPane is tasWindowObject.TasWindow.
Has a fdf and a none fdf verions. The noFdf version has no border/box Textures for the content pane. Only the demo map contains the fdf version.
282146-f2bf6191ada7b1e713587034ff691891.png

Lua:
--[[
    TasWindow V1.3 (NoFdF) by Tasyen
    The idea of TasWindow is to have a standart Frame in which you only have to care about how to manage your content onto the ContentPane without bothering the border etc.    
    nofdf has no window textures
    
function TasWindow.create([title, hide, createContext, parent])
    creates a window using the local players race border.
    A TasWindow consists of a Pane, a Head, a Title a closeButton and a Border.
    The Pane is mean to carry your custom Frame and contains only the space between the borders of the TasWindow.
    The closeButton is part of the Head and has 2 modes:
        hide(true) close the window and head when clicked for the local Player. In such a case the user needs a way to show the window.WindowHead again, if that is wanted.
        hide (false or nil) The close Button toggles the visibility of the TasWindow, the WindowHead remains visibile.
    createContext nil = 0, use a specific one, if you want to access frames over BlzGetFrameByName
    parent nil = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0).
    The window is posed over windowTable.WindowHead, all other frames of window are linked based on the heads position.
    returns the new created windowTable

function TasWindow.setAbsPoint(windowTable, framepoint, x, y)
function TasWindow.setSize(windowTable[, xSize, ySize, tempChange])
    without any arguments reset the size to the last non tempChange one
    without tempChange the window will change its current size and define a new default size

function TasWindow.replaceBackDrop(windowTable, newFrame)
    replaces the window background and border Backdrop with an given newFrame

you can set an TasWindow action that happens when the Close Button is clicked, visible is an async value.
    windowTable.UserAction = function(windowTable, player, visible) end

--]]

TasWindow = {
    CharClose = "X"
    ,CharExpand = "v"
    ,CharColapse = "^"
}
Window = TasWindow -- backwards compatible remove when unneeded
function TasWindow.create(title, hide, createContext, parent)
    local windowTable = {}
    if not createContext then createContext = 0 end --user does not care use 0.
    if not parent then parent = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0) end
    windowTable.WindowHead = BlzCreateFrameByType("GLUETEXTBUTTON", "WindowHead", parent, "ScriptDialogButton", createContext)
    windowTable.WindowCloseButton = BlzCreateFrameByType("GLUETEXTBUTTON", "WindowCloseButton", windowTable.WindowHead, "ScriptDialogButton", createContext) --press this to hide the window
    windowTable.WindowCloseButtonType = hide
    if hide then BlzFrameSetText(windowTable.WindowCloseButton, TasWindow.CharClose) else BlzFrameSetText(windowTable.WindowCloseButton, TasWindow.CharColapse) end
    
    BlzFrameSetSize(windowTable.WindowCloseButton, 0.0275, 0.0275)
    
    windowTable.WindowPane = BlzCreateFrameByType("SLIDER", "WindowPane", windowTable.WindowHead, "", createContext)
    windowTable.TasWindow = windowTable.WindowPane
    if title then
        BlzFrameSetText(windowTable.WindowHead, title)
    end
    BlzFrameSetSize(windowTable.WindowHead, 0.1725, 0.0275)
    BlzFrameSetPoint(windowTable.WindowPane, FRAMEPOINT_TOPLEFT, windowTable.WindowHead, FRAMEPOINT_BOTTOMLEFT, 0, 0.001)
    BlzFrameSetPoint(windowTable.WindowCloseButton, FRAMEPOINT_LEFT, windowTable.WindowHead, FRAMEPOINT_RIGHT, -0.005, 0)
    BlzFrameSetSize(windowTable.WindowPane, 0.18, 0.18)

    windowTable.WindowSizeX = BlzFrameGetWidth(windowTable.TasWindow)
    windowTable.WindowSizeY = BlzFrameGetHeight(windowTable.TasWindow)


    TasWindow[windowTable.TasWindow] = windowTable --the TasWindow and the WindowHead know the table, the others know the TasWindow by using BlzFrameGetParent
    TasWindow[windowTable.WindowHead] = windowTable

    TasButtonAction(windowTable.WindowHead, TasWindow.HeadAction)
    TasButtonAction(windowTable.WindowCloseButton, TasWindow.CloseButtonAction)

    return windowTable
end

function TasWindow.setAbsPoint(windowTable, framepoint, x, y)
    BlzFrameSetAbsPoint(windowTable.WindowHead, framepoint, x, y)
end


function TasWindow.setSize(windowTable, xSize, ySize, tempChange)
    if xSize then
        BlzFrameSetSize(windowTable.TasWindow, xSize, ySize)
        BlzFrameSetSize(windowTable.WindowHead, xSize - 0.025, 0.0275) -- -0.025 is the closebutton
        if not tempChange then
            windowTable.WindowSizeX = xSize
            windowTable.WindowSizeY = ySize
        end
    else
        BlzFrameSetSize(windowTable.TasWindow, windowTable.WindowSizeX, windowTable.WindowSizeY)
        BlzFrameSetSize(windowTable.WindowHead, windowTable.WindowSizeX - 0.025 , 0.0275)
    end
end

function TasWindow.HeadAction(frame, player)
   --when the title is clicked(released)
end

--more of an attribute hence CamelCase
function TasWindow.CloseButtonAction(frame, player)
    local windowTable = TasWindow[BlzFrameGetParent(frame)]
    if GetLocalPlayer() == player then
        if not windowTable.WindowCloseButtonType then
            BlzFrameSetVisible(windowTable.TasWindow, not BlzFrameIsVisible(windowTable.TasWindow))
            if BlzFrameIsVisible(windowTable.TasWindow) then BlzFrameSetText(windowTable.WindowCloseButton, TasWindow.CharColapse) else BlzFrameSetText(windowTable.WindowCloseButton, TasWindow.CharExpand) end
        else
            BlzFrameSetVisible(windowTable.WindowHead, false)
        end
        
    end
    if windowTable.UserAction then windowTable.UserAction(windowTable, player, BlzFrameIsVisible(windowTable.TasWindow)) end
end

TasWindowTab


Addon for TasWindow, it gets a page feature. The user can swap the current shown Page with Buttons (only swaps page for the local player).
Each Page is an unique Frame which you treat like the content pane in TasWindow. The Page is placed ontop of the Content Pane by making it a Tab.
282145-f505b4a918ec222ae1e50e40f683c67d.jpg

Lua:
--[[
    TasWindowTab NOFDF V1.2
    plugin for TasWindow by Tasyen.
    Instead of placing stuff onto the ContentPane one adds Frames as Tabs (pages). The current shown Tab is swaped by the user clicking TabButtons.
    First Create a TasWindow then add a frame as Tab to the TasWindow.
    Having a tab does not stopp one from placing something onto the ContentPane itself.

    function TasWindow.addTab(windowTable, frame, [buttonText, doNotStretch, xSize, ySize])
        adds frame as Tab to windowTable
        buttonText is displayed on the Button to swap to this tab
        doNotStretch(true) does not alter the size of frame, also pos it with its center to the WindowPane center
        xSize and ySize when set, will alter the size of windowTable as long this tab is shown
        Does not support SimpleFrames, directly.
        frames parent, position, size (without doNotStretch) are altered in the process.
        returns the new created windowTabtable

    function TasWindow.setTabButtonAction(windowTabTable, actionFunction)
        calls actionFunction when this button is clicked and shown.
        Beaware that the action is called async.
        Inside actionFunction you have windowTable, windowTabTable.
        Will instantly call the actionFunction if the tab is the current active tab

    function TasWindow.removeTab(windowTable[, windowTabTable])
        windowTabTable can be an index, a table or nil. nil will remove the last added one
        returns if windowTable has further Tabs remaining

    function TasWindow.showTab(windowTable, windowTabTable[, player])
        show windowTabTable of windowTable to player
        windowTabTable can be a index or a table, the table is expected to be a tabTable of the windowTable
        player can be nil to affect all players


doesn't work that well with LeaderBoard, Multiboard, TimerDialog
Does not support simpleframes.
--]]
function TasWindow.addTab(windowTable, frame, buttonText, doNotStretch, xSize, ySize)
    --each Tab is an own Table
    local windowTabTable = {}
    
    if not windowTable.Tabs then
        --this is the first time this window gets tabs
        windowTable.Tabs = {}
        windowTable.TabActive = windowTabTable
    end
    --add the new TabTable into the array of windowTable
    table.insert(windowTable.Tabs, windowTabTable)

    local tabButton = BlzCreateFrameByType("GLUETEXTBUTTON", "WindowTabButton", windowTable.WindowPane, "ScriptDialogButton", 0)
    if buttonText then
        BlzFrameSetText(tabButton, buttonText)
    else
        BlzFrameSetText(tabButton, #windowTable.Tabs)
    end
    BlzFrameSetSize(tabButton, 0.06, 0.025)

    TasWindow[tabButton] = windowTabTable
    TasWindow[windowTabTable] = windowTable
    --fit the given frame into the Content Pane?
    if not doNotStretch then
        BlzFrameSetAllPoints(frame, windowTable.WindowPane)
        BlzFrameSetSize(frame, BlzFrameGetWidth(windowTable.WindowPane), BlzFrameGetHeight(windowTable.WindowPane))
    else
        --only center it
        BlzFrameClearAllPoints(frame)
        BlzFrameSetPoint(frame, FRAMEPOINT_CENTER, windowTable.WindowPane, FRAMEPOINT_CENTER, 0, 0)
    end
    BlzFrameSetParent(frame, windowTable.WindowPane)
    
    windowTabTable.Button = tabButton
    windowTabTable.Frame = frame
    windowTabTable.SizeX = xSize
    windowTabTable.SizeY = ySize

    TasButtonAction(tabButton,  TasWindow.TabButtonAction)

    --pos the tab button
    if #windowTable.Tabs == 1 then
        --the first button is located at Top Left of the TasWindow
        BlzFrameSetVisible(frame, true)
        BlzFrameSetPoint(tabButton, FRAMEPOINT_TOPRIGHT, windowTable.TasWindow, FRAMEPOINT_TOPLEFT, 0, 0)
        --hide the new tab button, there is nothing to choose yet.
        BlzFrameSetVisible(windowTable.Tabs[1].Button, false)
        TasWindow.showTab(windowTable, windowTabTable)
    else
        --further ones are located below to the previous one
        --this is not the first added one hide it.
        
        BlzFrameSetVisible(frame, false)
        BlzFrameSetPoint(tabButton, FRAMEPOINT_TOP, windowTable.Tabs[#windowTable.Tabs - 1].Button, FRAMEPOINT_BOTTOM, 0, 0.005)
        BlzFrameSetVisible(windowTable.Tabs[1].Button, true)
    end
    return windowTabTable
end

function TasWindow.setTabButtonAction(windowTabTable, actionFunction)
    windowTabTable.ShowAction = actionFunction
    if TasWindow[windowTabTable].TabActive == windowTabTable then
        actionFunction(TasWindow[windowTabTable], windowTabTable)
    end
end

-- windowTabTable can be an index, a table or nil. nil will remove the last added one
-- returns true if there are tabs remaining
function TasWindow.removeTab(windowTable, windowTabTable)
    if #windowTable.Tabs == 0 then return false end
    if not windowTabTable then
        TasWindow.destroyTab(windowTable, #windowTable.Tabs, true)
    elseif type(windowTabTable) == "number" then
        TasWindow.destroyTab(windowTable, windowTabTable, true)
        
    elseif type(windowTabTable) == "table" then
        for index, value in ipairs(windowTable.Tabs)
        do
            if value == windowTabTable then
                TasWindow.destroyTab(windowTable, index, true)
                break
            end
        end
    end
    return #windowTable.Tabs > 0
end

function TasWindow.showTab(windowTable, windowTabTable, player)
    if player and player ~= GetLocalPlayer() then return end

    if windowTable.TabActive then
        BlzFrameSetVisible(windowTable.TabActive.Frame, false)
    end
    if type(windowTabTable) == "number" then
        windowTabTable = windowTable.Tabs[windowTabTable]
    end
    BlzFrameSetVisible(windowTabTable.Frame, true)
    windowTable.TabActive = windowTabTable

    if windowTabTable.SizeX then
        TasWindow.setSize(windowTable, windowTabTable.SizeX + 0.02, windowTabTable.SizeY + 0.02, true)
        BlzFrameSetSize(windowTabTable.Frame, BlzFrameGetWidth(windowTable.WindowPane), BlzFrameGetHeight(windowTable.WindowPane))
    else
        TasWindow.setSize(windowTable)
    end

    --custom user action when showing this Tab
    if windowTabTable.ShowAction then
        windowTabTable.ShowAction(windowTable, windowTabTable)
    end
end

--more of an attribute hence CamelCase
function TasWindow.TabButtonAction(button, player)
    local windowTable = TasWindow[BlzFrameGetParent(BlzFrameGetParent(button))]
    local windowTabTable = TasWindow[button]
    if GetLocalPlayer() == player then
        TasWindow.showTab(windowTable, windowTabTable)
    end
end

TasSliderControl


A Slider with text and tooltips is mostly here for the more adv demo. That shows the TasWindowTab + TasFrameList.
this Requires Loading ui\framedef\ui\escmenutemplates.fdf
Lua:
--[[
    TasSliderControl V0.9 by Tasyen

    This generates Sliders with a Label and tooltips showing min max current value. The idea is to simple down slider usage.

function TasSliderControl.new(valueChangeActionFunction[, min, max, default, step, labelText, sizeText, sizeSlider, name, parent, createContext])
    this creates an slider with Label that executes valueChangeActionFunction when the value changes, the slider can be scrolled with the mouse whell.
    valueChangeActionFunction is called for all players when the sliders value changes, the function has one argument the sliderObject, normal FrameEvent getters are valid here.
    name is an suffix for all frames created by TasSliderControl, it only is relevant for BlzGetFrameByName or BlzFrameGetName
    sizeText + sizeSlider is the total screensize this takes
    default is the value reseted to when using TasSliderControl.reset
    the Label and Slider are placed into a container FRAME. Use returnValue.Frame to move/use the container.
    returns a table
    

function TasSliderControl.reset(sliderObject[, player])
    sets the slider of that sliderObject to the default Value will evoke the action, when not using player all players are affected

--]]

TasSliderControl = {}
TasSliderControl.PercentChar = "\x25"
SliderControl = TasSliderControl
TasSliderControl.ValueAction = function(frame, player, value)
    local sliderObject = TasSliderControl[frame]
    --update the current text to the new value, but only if the local player was the player who changed the value
    if GetLocalPlayer() == player then
        BlzFrameSetText(sliderObject.TextCurrent, string.format(sliderObject.Format, BlzFrameGetValue(frame)))
    end

    --when there is an action call it
    if sliderObject.Action then
        sliderObject.Action(sliderObject)
    end

end

function TasSliderControl.reset(sliderObject, player)
    if not player or GetLocalPlayer() == GetTriggerPlayer() then
        BlzFrameSetValue(sliderObject.Slider, sliderObject.Default)
    end
end

function TasSliderControl.new(valueChangeActionFunction, min, max, default, step, labelText, sizeText, sizeSlider, name, parent, createContext)
    BlzLoadTOCFile("war3mapimported\\templates.toc") --loads ui\framedef\ui\escmenutemplates.fdf
    local newObject = {}
    --setup unset data
    if not createContext then createContext = 0 end
    if not parent then parent = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0) end
    if not name then name = "" end
    if not step then step = 1 end
    if not sizeSlider then sizeSlider = 0.12 end
    if not sizeText then sizeText = 0.12 end
    if not min then min = 1 end
    if not max then max = 100 end
    if not default then default =max/2 end
    if not step then step = 1 end

    newObject.Format = TasSliderControl.PercentChar..".1f"
    newObject.Action = valueChangeActionFunction
    --this is the container of the Slider and Label
    newObject.Frame = BlzCreateFrameByType("FRAME", "SliderControlFrame_"..name, parent, "", createContext)
    BlzFrameSetSize(newObject.Frame, sizeText + sizeSlider, 0.013)
    BlzFrameSetEnable(newObject.Frame, false)

    newObject.Slider = BlzCreateFrameByType("SLIDER", "SliderControlSlider_"..name, newObject.Frame, "EscMenuSliderTemplate", createContext)
    TasSliderControl[newObject.Slider] = newObject
    BlzFrameSetSize(newObject.Slider, sizeSlider, 0.012)
    BlzFrameSetMinMaxValue(newObject.Slider, min, max)
    BlzFrameSetStepSize(newObject.Slider, step)
    BlzFrameSetValue(newObject.Slider, default)
    newObject.StepSize = step
    newObject.Default = default

    TasSliderAction(newObject.Slider, TasSliderControl.ValueAction, step)
    
    newObject.Label = BlzCreateFrameByType("TEXT", "SliderControlLabel_"..name, newObject.Frame, "EscMenuMainPanelDialogTextTemplate", createContext)
    BlzFrameSetText(newObject.Label, labelText)

    newObject.Tooltip = BlzCreateFrameByType("FRAME", "SliderControlTooltip_"..name, newObject.Frame, "", createContext)
    newObject.TextMin = BlzCreateFrameByType("TEXT", "SliderControlTextMin_"..name, newObject.Tooltip, "EscMenuMainPanelDialogTextTemplate", createContext)
    newObject.TextMax = BlzCreateFrameByType("TEXT", "SliderControlTextMax_"..name, newObject.Tooltip, "EscMenuMainPanelDialogTextTemplate", createContext)
    newObject.TextCurrent = BlzCreateFrameByType("TEXT", "SliderControlTextCurrent_"..name, newObject.Tooltip, "EscMenuMainPanelDialogTextTemplate", createContext)

    BlzFrameSetText(newObject.TextMin, min)
    BlzFrameSetText(newObject.TextMax, max)
    BlzFrameSetText(newObject.TextCurrent, string.format(newObject.Format, BlzFrameGetValue(newObject.Slider)))
    BlzFrameSetEnable(newObject.Tooltip, false)
    BlzFrameSetTooltip(newObject.Slider, newObject.Tooltip)

    BlzFrameSetPoint(newObject.TextMin, FRAMEPOINT_BOTTOM, newObject.Slider, FRAMEPOINT_TOPLEFT, 0, 0)
    BlzFrameSetPoint(newObject.TextMax, FRAMEPOINT_BOTTOM, newObject.Slider, FRAMEPOINT_TOPRIGHT, 0, 0)
    BlzFrameSetPoint(newObject.TextCurrent, FRAMEPOINT_BOTTOM, newObject.Slider, FRAMEPOINT_TOP, 0, 0)

    BlzFrameSetPoint(newObject.Label, FRAMEPOINT_LEFT, newObject.Frame, FRAMEPOINT_LEFT, 0, 0)
    BlzFrameSetPoint(newObject.Slider, FRAMEPOINT_RIGHT, newObject.Frame, FRAMEPOINT_RIGHT, 0, 0)

    return newObject
end

Tags: Custom UI, Container, Layout, Slider, List, FrameList, Tab,​
Contents

TasUIContainers (Map)

Reviews
Antares
You can shorten these lines like so if not createContext then createContext = 0 end --=> createContext = createContext or 0 For some of your resources, it's a bit hard to grasp what exactly they're doing. You could insert the images you have attached...
You can shorten these lines like so
Lua:
if not createContext then createContext = 0 end
--=>
createContext = createContext or 0

For some of your resources, it's a bit hard to grasp what exactly they're doing. You could insert the images you have attached directly into the text of the respective resource so that it's easier to follow. I think you would also benefit from an AI assistant helping you with your descriptions, since your English isn't as impeccable as your code.

Anyway, these have all been reviewed before. Good idea to compile them into a single pack.

Approved
 
Updated TasWindow to V1.3)
added (suggested by bribe in the old post in code archive)
TasWindow.CharClose = "X"
TasWindow.CharExpand = "v"
TasWindow.CharColapse = "^"
This chars are displayed in the closeButton for this states.

you can set an TasWindow action that happens when the Close Button is clicked, visible is an async value.
windowTable.UserAction = function(windowTable, player, visible) end
 
Updated TasFrameList to V1.2)
It does now not require TasFrameAction, as it is written.
Each frameListObject can have an additional callback for custom updates. The callback is called when TasFrameList.update(frameListTable) runs. Which also happens by user scrolling.
frameListTable.Action = function(frameListTable) end

Updated to TasFrameFlow V1.1)
added the updated callback like for TasFrameList; function frameFlowTable.Action(frameFlowTable) end

the demo map includes now TasFrameAction V1.3.
 
Last edited:
Top