Добавлен , опубликован

Основы Интерфейса

Содержание:
ссылка
кратко: это наработка позволяет располагать внутри окна-фрейма другие фреймы. Ранее мы изучали AllianceDialog, там можно расположить все фреймы и информацию о каждом игроке в строку. Конечно, все фреймы могут не влезть в окно, и поэтому в нашем окно располагается только определенная часть. Та часть, что не влезла, ее не видно. Обязательно в таких наработках присутствует scrollbars/sliders или кнопки переключения - они меняют положение фреймов внутри окна. Короче, наработка работает прежде всего с размерами фрейма, зная размеры: ширина, высота, координаты, вы можете перемещать.
FrameFlow - это наработка, которая управляет положением фреймов в фрейме, если они добавляются через FrameFlow. Фреймам, которые используются и добавляются FrameFlow, требуется размер, и этот размер соблюдается. Поэтому фреймы, которые не влезли в фрейм, управляемый FrameFlow, будут скрыты. Можно изменить начальный фрейм, чтобы отобразить такие более поздние фрейм, FrameFlow может добавить sliders/scrollbar, когда это необходимо. У этой наработки нет импорта: Toc или файла fdf.
FrameFlow работает как на этом изображении: 1, 2 и 3 помещаются в один ряд. 4-ый фрейм будет слишком большой, чтобы находиться в той же строке, поэтому она начинает новую строку, но учитывает размер 2 и 3, которые занимают больше ySize, чем 1, следовательно, есть промежуток между 1 и 4.
7-ой добавляется после 6-ого. Кадр 7 выглядит так, как будто он может уместиться где-нибудь еще, но FrameFlow не делает этого. Он добавляет новые кадры после предыдущего, как сказано выше, или запускает новую строку, когда это необходимо.
6-ой фрейм не будет отображаться, потому что он займет пространство за пределами ParentFrame. Но 7 все равно будет рядом с этим скрытым фреймом, в результате чего будет один фрейм в центре.
Код системы FrameFlow
--[[
    FrameFlow V0.9b by Tasyen
    FrameFlow 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 FrameFlow 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 FrameFlow and the frames added need a size for this system to work.
 

    function FrameFlow.create(frame[, addSlider, marginX, marginY])
        creates a new FrameFlow 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 FrameFlow.updateSlider.

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

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

    function FrameFlow.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 FrameFlow

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

FrameFlow = {}
-- creates a new FrameFlow filling frame
function FrameFlow.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)
        FrameFlow[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)
        frameFlowTable.SliderTrigger = CreateTrigger()
        frameFlowTable.SliderTriggerAction = TriggerAddAction(frameFlowTable.SliderTrigger, FrameFlow.SliderAction)
        BlzTriggerRegisterFrameEvent(frameFlowTable.SliderTrigger, frameFlowTable.Slider , FRAMEEVENT_SLIDER_VALUE_CHANGED)
        BlzTriggerRegisterFrameEvent(frameFlowTable.SliderTrigger, frameFlowTable.Slider , FRAMEEVENT_MOUSE_WHEEL)
    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 FrameFlow.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 FrameFlow.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]
        FrameFlow.calc(frameFlowTable, frame, prevFrame)
 
        prevFrame = frame
    end
end

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

function FrameFlow.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
            FrameFlow.fit(frameFlowTable, 1)
        end
    end
    return #frameFlowTable.Content
end

function FrameFlow.destroy(frameFlowTable)
    if frameFlowTable.Slider then
        FrameFlow[frameFlowTable.Slider] = nil
        TriggerRemoveAction(frameFlowTable.SliderTrigger, frameFlowTable.SliderTriggerAction)
        DestroyTrigger(frameFlowTable.SliderTrigger)
        BlzDestroyFrame(frameFlowTable.Slider)
        frameFlowTable.Slider = nil
        frameFlowTable.SliderTrigger = nil
        frameFlowTable.SliderTriggerAction = nil
    end
    frameFlowTable.Frame = nil
    frameFlowTable.Content = nil
    frameFlowTable.CurrentRowRemainX = nil
    frameFlowTable.CurrentRowSizeY = nil
    frameFlowTable.CurrentOffsetY = nil
end

function FrameFlow.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
            FrameFlow.fit(frameFlowTable, 1)
        else
            FrameFlow.fitNewFrame(frameFlowTable, frame)
        end
    end
end

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

function FrameFlow.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
        FrameFlow.fit(FrameFlow[frame],  BlzFrameGetValue(frame))
    end
end
пример использования
Может быть не понятно как пользоваться, поэтому предоставлен пример:
do
    local real = MarkGameStarted
  function MarkGameStarted()
        real()
    xpcall(function()
    local gameUI = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
    local parentFrame = BlzCreateFrameByType("FRAME", "", gameUI, "", 0)
    BlzFrameSetAbsPoint(parentFrame, FRAMEPOINT_CENTER, 0.4, 0.3)
    BlzFrameSetSize(parentFrame, 0.15, 0.22)
    local frameFlowTable = FrameFlow.create(parentFrame, 0.0005, 0.001)


    for index = 1, 11, 1 do

       local icon =  BlzCreateFrameByType("BACKDROP", "MYIcon", gameUI, "", 0)
       BlzFrameSetTexture(icon, "ReplaceableTextures\\CommandButtons\\BTNHeroPaladin",0, false)
       BlzFrameSetSize(icon, 0.03, 0.03)
       FrameFlow.add(frameFlowTable, icon)
    end
    icon =  BlzCreateFrameByType("BACKDROP", "MYIcon", gameUI, "", 0)
    BlzFrameSetTexture(icon, "ReplaceableTextures\\CommandButtons\\BTNHeroArchMage",0, false)
    BlzFrameSetSize(icon, 0.08, 0.08)
    FrameFlow.add(frameFlowTable, icon)

    icon =  BlzCreateFrameByType("BACKDROP", "MYIcon", gameUI, "", 0)
    BlzFrameSetSize(icon, 0.1, 0.1)
    BlzFrameSetTexture(icon, "ReplaceableTextures\\CommandButtons\\BTNHeroMountainKing",0, false)
    FrameFlow.add(frameFlowTable, icon)
    icon =  BlzCreateFrameByType("BACKDROP", "MYIcon", gameUI, "", 0)
    BlzFrameSetTexture(icon, "ReplaceableTextures\\CommandButtons\\BTNHeroBloodElfPrince",0, false)
    BlzFrameSetSize(icon, 0.08, 0.04)
    FrameFlow.add(frameFlowTable, icon)
    end,err)
  end
end
то, что должно влезь в окно
как они будут расположены в окне

Содержание
`
ОЖИДАНИЕ РЕКЛАМЫ...