• 🏆 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!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[Lua] UI - Move Able Frame

This is a Lua resource that allows to make Frames moveable by the user using drag and drop. The user right clicks a frame and while he holds the right mouse button the frame will follow the mouse. Only frames supporting a Frame Mouse Enter event can be made move able with this resource.
It uses a modified version of global init from Bribe.

How this get the mouse screen position when there is not GetMouseScreenPos?
It creates a grid of invisible Frames each knowing its own position each such frame has a tooltip if that tooltip is visible the mouse is on its position. This requires an huge amount of frames ~10k.
This grid is the system FrameGrid.
Lua:
--[[FrameGrid by Tasyen
--Got that Idea from CanFight, he mentioned something about a FPS game in which he clustered the screen with Frames to know the mouse position.
function FrameGrid.show(flag, player)
    show/hide the grid for player nil or GetLocalPlayer affect all players
--]]
FrameGrid = {}
FrameGrid.Boss = nil --the parent hide/show it to enable/disable the functionality of this system.
FrameGrid.GridFrames = {} --all grid frames
FrameGrid.GridFrames2 = {} --the tooltip frames of the grid
FrameGrid.LastFrame = 0 --the index of the frame hovered by the mouse, might be incorrect sometimes
onGameStart(function()
    --        print("FrameGrid.Init")
       
    FrameGrid.Timer = CreateTimer()
    TimerStart(FrameGrid.Timer, 0.01, true, FrameGrid.update)
    --the Grid Boss Frame its a BUTTON so it can have a higher Frame Level.
    --This Frame is used as on/off, when showing it the FrameGrid becomes active while it does nothing when Boss is disabled.
    FrameGrid.Boss = BlzCreateFrameByType("BUTTON", "FrameGridBoss", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0)
    --be above other frames, using this allows to move into other frames but also stops their mouse enter events while FrameGrid is active.
    --I wasn't able to change this value at a later time hence there is no swap for this.
    --BlzFrameSetLevel(FrameGrid.Boss, 7)
  
    local xSize = 0.01 --dont go to low
    local ySize = 0.01 --dont go to low
    local yStart = ySize/2
    local xStart = xSize/2
    FrameGrid.FramesEachCol = 0.6 / ySize
    for x = xStart, 0.8, xSize do
        for y = yStart, 0.6, ySize do
            local newButton = BlzCreateFrameByType("FRAME", "", FrameGrid.Boss,"",0)
            local tooltipButton = BlzCreateFrameByType("FRAME", "", FrameGrid.Boss,"",0)
            BlzFrameSetAbsPoint(newButton, FRAMEPOINT_CENTER, x, y)
            BlzFrameSetSize(newButton, xSize, ySize)
            BlzFrameSetTooltip(newButton, tooltipButton)
            BlzFrameSetEnable(newButton, false)
            BlzFrameSetEnable(tooltipButton, false)
            FrameGrid[newButton] = {x, y}
            FrameGrid[tooltipButton] = {x, y}
            table.insert(FrameGrid.GridFrames, newButton)
            table.insert(FrameGrid.GridFrames2, tooltipButton)
        end
    end
   
    BlzFrameSetVisible(FrameGrid.Boss, false)
end)

function FrameGrid.updateSimple()
    --Grid visible?
    if BlzFrameIsVisible(FrameGrid.Boss) then
        --loop all Tooltip Frames and find the visible one. The visible one is the position of the mouse on the screen.
        --this is a bit inefficent in worst case one iterates 4800 times, frames are saved in col wise means as farer left the mouse is as faster this is done.
        --when beeing at left it only takes no os.clock time while it takes ~ 0.003 or 0.005  seconds on the right
        --local count = 0
        --local time = os.clock()
        for index, value in ipairs(FrameGrid.GridFrames2)
        do
            --count = count + 1
            if BlzFrameIsVisible(value) then
          --      FrameGrid.LastY = FrameGrid[value][2]
                MoveAbleFrame.moveFrame(FrameGrid[value][1], FrameGrid[value][2])
                break
            end
        end
        --print(count)
        --print("count:",count, "os.clock", os.clock() - time)
       -- print(os.clock() - time)
    end
end

function FrameGrid.update()
    --Grid visible?
    if BlzFrameIsVisible(FrameGrid.Boss) then
        --search the visible Tooltip Frame in both directions from the last found position.
        --this way speeds it up when doing only small steps, average was for me 60 to 240 steps and resulting into 0 or sometimes ~0.0009 ~0.001 os.clock dif
       
        --local count = 0
        --local time = os.clock()
        local yA = FrameGrid.LastFrame
        local yB = FrameGrid.LastFrame
       
        while (yA > 0 or yB < 4800)
        do
            --count = count + 1
            if yA >= 0 then
                if BlzFrameIsVisible(FrameGrid.GridFrames2[yA]) then
                    FrameGrid.LastFrame = yA
                    MoveAbleFrame.moveFrame(FrameGrid[FrameGrid.GridFrames2[yA]][1], FrameGrid[FrameGrid.GridFrames2[yA]][2])
                    break
                end
                yA = yA - 1
            end
            if BlzFrameIsVisible(FrameGrid.GridFrames2[yB]) then
                FrameGrid.LastFrame = yB
                MoveAbleFrame.moveFrame(FrameGrid[FrameGrid.GridFrames2[yB]][1], FrameGrid[FrameGrid.GridFrames2[yB]][2])
                break
            else
                yB = yB + 1
            end
        end
        --print("count:",count, "os.clock", os.clock() - time)
        --print(os.clock() - time)
    end
end

function FrameGrid.show(flag, player)
    if not player or GetLocalPlayer() == player then
        BlzFrameSetVisible(FrameGrid.Boss, flag)
    end
end

The moveable System is this one:
Lua:
--[[
MoveAbleFrame (Mini) by Tasyen
MoveAbleFrame allows to drag&drop frames you have setuped to be moveable. This System is async do not use anthing of it in a sync manner. (Mini) does not save frame positions

function MoveAbleFrame.setup(frame)
    makes this frame moveable by user with drag and drop, only works on frameTypes supporting FRAMEEVENT_MOUSE_ENTER and FRAMEEVENT_MOUSE_LEAVE
    has to be called sync cause it creates events, unlike the other userMoveAbleFrame functions which should be used async
    The user changed position can be saved in a file and loaded. The frames are identyfied by the order, they were added to userMoveAbleFrame.
    Means when adding new userMoveAbleFrames not to the end (order wise), then a saved File can move a wrong frame when loading an File saved with an old version.

function MoveAbleFrame.enable(player[, flag])
    (dis)allows drag and drop moveable Frames for player, use GetLocalPlayer() to affect all players
    can be called without flag in such a case the current value is negated. true <-> false
    this has no impact on current done drag&dropping
    returns the value of MoveAbleFrame.Enabled
--]]
MoveAbleFrame = {}
MoveAbleFrame.Enabled = false --only when this is true, right clicking will have an effect on frames
MoveAbleFrame.Frame = nil -- the Frame beeing Moved
MoveAbleFrame.FramePoint = nil -- the FramePoint Frame is posed with nil = CENTER

function MoveAbleFrame.startMoving(frame, framePoint)
    MoveAbleFrame.Frame = frame
    if not framePoint then
       framePoint = FRAMEPOINT_CENTER
    end
    MoveAbleFrame.FramePoint = framePoint
    FrameGrid.show(true)
end

function MoveAbleFrame.moveFrame(x, y, finish)
    BlzFrameClearAllPoints(MoveAbleFrame.Frame)
    BlzFrameSetAbsPoint(MoveAbleFrame.Frame, MoveAbleFrame.FramePoint, x, y)
    if finish then
        FrameGrid.show(false)
    end
end

function MoveAbleFrame.enable(player, flag)
    if GetLocalPlayer() == player then
        if flag == nil then
            MoveAbleFrame.Enabled = not MoveAbleFrame.Enabled
        else
            MoveAbleFrame.Enabled = flag
        end
    end
    return MoveAbleFrame.Enabled
end

function MoveAbleFrame.setup(frame)
    if not MoveAbleFrame[frame] then
        MoveAbleFrame[frame] = true

        BlzTriggerRegisterFrameEvent(MoveAbleFrame.TriggerFrameEnter, frame, FRAMEEVENT_MOUSE_ENTER) --enable the hover feature
        BlzTriggerRegisterFrameEvent(MoveAbleFrame.TriggerFrameLeave , frame, FRAMEEVENT_MOUSE_LEAVE)
    end

end

onTriggerInit(function()
    xpcall(function()
    --        print("MoveAbleFrame.Init")

    --this is the FrameEnter Event trigger, every moveable Frame calls it, when entering remember the entere Frame
    MoveAbleFrame.TriggerFrameEnter = CreateTrigger()
    MoveAbleFrame.TriggerFrameEnterAction = TriggerAddAction(MoveAbleFrame.TriggerFrameEnter, function()
        if GetLocalPlayer() == GetTriggerPlayer() then
            MoveAbleFrame.PlayerHoveredFrame = BlzGetTriggerFrame()
        end
    end)

    MoveAbleFrame.TriggerFrameLeave = CreateTrigger()
    MoveAbleFrame.TriggerFrameLeaveAction = TriggerAddAction(MoveAbleFrame.TriggerFrameLeave, function()
        if GetLocalPlayer() == GetTriggerPlayer() then
            MoveAbleFrame.PlayerHoveredFrame = nil
        end
    end)

    MoveAbleFrame.MouseClickTrigger = CreateTrigger()
    MoveAbleFrame.MouseClickTriggerAction = TriggerAddAction(MoveAbleFrame.MouseClickTrigger, function()
        if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
            local player = GetTriggerPlayer()
            if MoveAbleFrame.PlayerHoveredFrame then
                --UI Edit Mode start moving that frame
                if MoveAbleFrame.Enabled then
                    if GetLocalPlayer() == player then
                        MoveAbleFrame.startMoving(MoveAbleFrame.PlayerHoveredFrame)
                        --disable the moving frame so it does not send mouse enter events, is more accurate to move and other frames are better respecected
                        BlzFrameSetEnable(MoveAbleFrame.PlayerHoveredFrame, false)
                    end
                end
            end
        end
    end)
    MoveAbleFrame.MouseReleaseTrigger = CreateTrigger()
    MoveAbleFrame.MouseReleaseTriggerAction = TriggerAddAction(MoveAbleFrame.MouseReleaseTrigger, function()
        if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
            --reenable the movedFrame, if there is one
            if MoveAbleFrame.Frame then
                BlzFrameSetEnable(MoveAbleFrame.Frame, true)
            end
            --UI Edit Mode start moving that frame
            FrameGrid.show(false, GetTriggerPlayer())
        end
    end)
  
    for playerIndex = 0, GetBJMaxPlayers()-1,1 do
        TriggerRegisterPlayerEvent(MoveAbleFrame.MouseClickTrigger, Player(playerIndex), EVENT_PLAYER_MOUSE_DOWN)
        TriggerRegisterPlayerEvent(MoveAbleFrame.MouseReleaseTrigger, Player(playerIndex), EVENT_PLAYER_MOUSE_UP)
    end
end, err)
end)
 

Attachments

  • MoveAbleFrame - Mini Tooltip based.w3x
    24.5 KB · Views: 301
Level 6
Joined
Aug 28, 2015
Messages
213
I hope that GetMouseScreenPos will be included to reforge soon™ but otherwise wouldn't it be more efficient to 'just' create a grid around the courser and move the grid having the middle of the hovered frame a middle point. I think you could cut down on frames like this drastically.
Maybe the full screen grid can be used to re-catch the courser using the mouse move native, and then swap back to the surrounding system.
 
Thanks for your Input.
I hope that GetMouseScreenPos will be included to reforge soon™
I hope so too.

but otherwise wouldn't it be more efficient to 'just' create a grid around the courser and move the grid having the middle of the hovered frame a middle point. I think you could cut down on frames like this drastically.
Maybe the full screen grid can be used to re-catch the courser using the mouse move native, and then swap back to the surrounding system.
Sounds good having big sections and a small accurate grid, the small would move to the current section. Yeah that would drastically reduce the amount of frames and with that checks per timeout. But one would have to test how good that works in the game. I also thinked with such an Idea (which did not turn out so well) but yours sound better.

Recently I tried to cover the 16:9 screen part by using SIMPLEBUTTONs for the grid. But this simpleButtons took over all mouse input which can be quite ugly if one wants interactions with other frames. And they did not overtake the screenspace the existing SIMPLE Frames take (hero buttons, menu buttons, unitinfos, command buttons, itembuttons...)

Edit: Works quite well: A prototype
Lua:
--[[FrameGrid Section by Tasyen
-- Got that Idea from CanFight, he mentioned something about a FPS game in which he clustered the screen with Frames to know the mouse position.
-- Sectoion built in an idea from apsyll. The screen is splited into sections of equal size and the framegride the one with the many small frames covers only one section.
-- the grid is moved to the current active Section. Then the position inside the grid is added to the position of the active section. That reduces the amount of frames and with that the amount of checks per timeout quite much also allows a more accurate grid.

function FrameGrid.show(flag, player)
    show/hide the grid for player nil or GetLocalPlayer affect all players

--]]

FrameGrid = {}

FrameGrid.Sections = {}
FrameGrid.Boss = nil --the parent hide/show it to enable/disable the functionality of this system.
FrameGrid.GridFrames = {} --all grid frames
FrameGrid.GridFrames2 = {} --the tooltip frames of the grid
FrameGrid.SectionFrames = {} --all grid frames
FrameGrid.SectionFrames2 = {} --the tooltip frames of the grid
FrameGrid.LastFrame = 0 --the index of the frame hovered by the mouse, might be incorrect sometimes
FrameGrid.ActiveSection = nil
FrameGrid.SectionFoundCounter = 0 -- there is a small delay needed when swaping from section to grid mode.
FrameGrid.SectionSizeX = 0.2 
FrameGrid.SectionSizeY = 0.2
onGameStart(function()
    --        print("FrameGrid.Init")
        xpcall(function()
    FrameGrid.Timer = CreateTimer()
    TimerStart(FrameGrid.Timer, 0.01, true, FrameGrid.updateSimple)

    --the Grid Boss Frame its a BUTTON so it can have a higher Frame Level.
    --This Frame is used as on/off, when showing it the FrameGrid becomes active while it does nothing when Boss is disabled.
    FrameGrid.Boss = BlzCreateFrameByType("BUTTON", "FrameGridBoss", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0)
    FrameGrid.BossGrid = BlzCreateFrameByType("FRAME", "FrameGridBoss", FrameGrid.Boss,"",0)
    FrameGrid.BossSections = BlzCreateFrameByType("FRAME", "FrameGridBoss", FrameGrid.Boss,"",0)

    FrameGrid.PosFrame = BlzCreateFrameByType("FRAME", "FrameGridGridPos", FrameGrid.Boss,"",0)
    BlzFrameSetSize(FrameGrid.PosFrame, 0.0001, 0.0001)
    BlzFrameSetEnable(FrameGrid.PosFrame, false)

    --be above other frames, using this allows to move into other frames but also stops their mouse enter events while FrameGrid is active.
    --I wasn't able to change this value at a later time hence there is no swap for this.
    --BlzFrameSetLevel(FrameGrid.Boss, 7)
   
   

    local sectionSizeX = FrameGrid.SectionSizeX
    local sectionSizeY = FrameGrid.SectionSizeY
    for x = 0, 0.8 - sectionSizeX, sectionSizeX do
        for y = 0, 0.6 - sectionSizeY, sectionSizeY do
            local sectionFrame = BlzCreateFrameByType("FRAME", "", FrameGrid.BossSections,"",0)
            local tooltipSection = BlzCreateFrameByType("FRAME", "", FrameGrid.BossSections,"",0)
            BlzFrameSetSize(sectionFrame, sectionSizeX, sectionSizeY)
            print(x, y)
            -- without +0.0001" the bottom row failed
            BlzFrameSetAbsPoint(sectionFrame, FRAMEPOINT_BOTTOMLEFT, x, y + 0.0001)
            BlzFrameSetEnable(sectionFrame, false)
            BlzFrameSetEnable(tooltipSection, false)
            BlzFrameSetTooltip(sectionFrame, tooltipSection)
            FrameGrid[sectionFrame] = {x, y}
            FrameGrid[tooltipSection] = {x, y}
            table.insert(FrameGrid.SectionFrames, sectionFrame)
            table.insert(FrameGrid.SectionFrames2, tooltipSection)
        end
    end
    --BlzFrameSetAbsPoint(FrameGrid.PosFrame, FRAMEPOINT_TOPLEFT, 0, 0.0)
   
    local xSize = 0.008 --dont go to low
    local ySize = 0.008 --dont go to low
    local yStart = ySize/2
    local xStart = xSize/2
   
    for x = xStart, sectionSizeX, xSize do
        for y = yStart, sectionSizeY, ySize do
            local newButton = BlzCreateFrameByType("FRAME", "", FrameGrid.BossGrid,"",0)
            local tooltipButton = BlzCreateFrameByType("FRAME", "", FrameGrid.BossGrid,"",0)
            --BlzFrameSetAbsPoint(newButton, FRAMEPOINT_CENTER, x, y)
            BlzFrameSetPoint(newButton, FRAMEPOINT_CENTER, FrameGrid.PosFrame, FRAMEPOINT_TOPLEFT, x, y)
            BlzFrameSetSize(newButton, xSize, ySize)
            BlzFrameSetTooltip(newButton, tooltipButton)
            BlzFrameSetEnable(newButton, false)
            BlzFrameSetEnable(tooltipButton, false)
            FrameGrid[newButton] = {x, y}
            FrameGrid[tooltipButton] = {x, y}
            table.insert(FrameGrid.GridFrames, newButton)
            table.insert(FrameGrid.GridFrames2, tooltipButton)
        end
    end
   
    BlzFrameSetVisible(FrameGrid.Boss, false)
    BlzFrameSetVisible(FrameGrid.BossSections, true)
    BlzFrameSetVisible(FrameGrid.BossGrid, false)
end, function(err) print(err) return err end)
end)

function FrameGrid.updateSimple()
    --Grid visible?
    xpcall(function()
    if BlzFrameIsVisible(FrameGrid.Boss) then
        -- loop all Tooltip Frames of the grid and find the visible one. The visible one is the position of the mouse inside the current section.

        --local count = 0
        --local time = os.clock()
        local inGrid = false
        if FrameGrid.ActiveSection then
            for index, value in ipairs(FrameGrid.GridFrames2)
            do
                if BlzFrameIsVisible(value) then
            --      FrameGrid.LastY = FrameGrid[value][2]
                    local x = FrameGrid[value][1]
                    local y = FrameGrid[value][2]
                   
                    --print("In Grid",x, y)
                    local xSection = FrameGrid[FrameGrid.ActiveSection][1]
                    local ySection = FrameGrid[FrameGrid.ActiveSection][2]
                    --MoveAbleFrame.moveFrame(x + xSection, y + ySection)
                    print("Mouse On screen", string.format( "%%.3f",x + xSection), string.format( "%%.3f",y + ySection))
                    inGrid = true
                    break
                end
            end
        end

        -- mouse is outside of the grid?
        if not inGrid then
            -- yes, did the new section Counter drop to 0 yet.
            if FrameGrid.SectionFoundCounter <= 0 then
                FrameGrid.ActiveSection = nil
                -- swap grid off and Sections on
                BlzFrameSetVisible(FrameGrid.BossSections, true)
                BlzFrameSetVisible(FrameGrid.BossGrid, false)

                -- search the active section
                for index, value in ipairs(FrameGrid.SectionFrames2)
                do
                    if BlzFrameIsVisible(value) then
                        FrameGrid.ActiveSection = FrameGrid.SectionFrames[index]
                        BlzFrameSetPoint(FrameGrid.PosFrame, FRAMEPOINT_TOPLEFT, FrameGrid.SectionFrames[index], FRAMEPOINT_BOTTOMLEFT, 0, 0)

                        -- swap grid on and section off
                        BlzFrameSetVisible(FrameGrid.BossSections, false)
                        BlzFrameSetVisible(FrameGrid.BossGrid, true)
                       
                        -- wait atleast 4 timer iterations before searching for a new section, .
                        FrameGrid.SectionFoundCounter = 2

    --                    print("In Section",x, y)
                        break
                    end
                end
            else
                FrameGrid.SectionFoundCounter = FrameGrid.SectionFoundCounter - 1
            end
        end
      --  print(count)
        --print("count:",count, "os.clock", os.clock() - time)
        --print(os.clock() - time)
    end
end, function(err) print(err) return err end)
end

function FrameGrid.show(flag, player)
    if not player or GetLocalPlayer() == player then
        BlzFrameSetVisible(FrameGrid.Boss, flag)
    end
end
 
Last edited:
Level 18
Joined
Oct 17, 2012
Messages
820
Do you have any plans of making a JASS version in the future? I tried converting this to JASS but failed.
Here is what I got so far:
JASS:
library FrameGrid requires Table

    struct FrameGrid extends array
        private Table table
      
        private static hashtable hash
      
        private static constant real SectionSizeX = 0.2
        private static constant real SectionSizeY = 0.2
      
        private static timer timer
      
        private static framehandle Boss
        private static framehandle BossGrid
        private static framehandle BossSections
        private static framehandle PosFrame
        private static framehandle ActiveSection = null
      
        private static integer SectionCount = 0
        private static integer GridCount = 0
        private static integer GridCount2 = 0
        private static integer SectionFrameCount = 0
        private static integer SectionFrameCount2 = 0
      
        private static integer SectionFoundCount = 0
        private static integer LastFrame
      
        private static method updateSimple takes nothing returns nothing
            local boolean inGrid
            local real x
            local real y
            local real xSection
            local real ySection
            local integer i = GridCount2
            local Table ta
            local framehandle frame
          
            if BlzFrameIsVisible(Boss) then
                set inGrid = false
                if ActiveSection != null then
                    loop
                        exitwhen i < 0
                        set frame = LoadFrameHandle(hash, 3, i)
                        if BlzFrameIsVisible(frame) then
                            set ta = FrameGrid(GetHandleId(frame)).table
                            set x = ta[1]
                            set y = ta[2]
                            set xSection = FrameGrid(GetHandleId(ActiveSection)).table[1]
                            set ySection = FrameGrid(GetHandleId(ActiveSection)).table[2]
                            call MoveAbleFrame.moveFrame(x + xSection, y + ySection, false)
                            set inGrid = true
                            exitwhen true
                        endif
                        set i = i - 1
                    endloop
                endif
              
                if not inGrid then
                    if SectionFoundCount <= 0 then
                        set ActiveSection = null
                      
                        call BlzFrameSetVisible(BossSections, true)
                        call BlzFrameSetVisible(BossGrid, false)
                        set i = SectionFrameCount2
                        loop
                            exitwhen i < 0
                            set frame = LoadFrameHandle(hash, 1, i)
                            if BlzFrameIsVisible(frame) then
                                set ActiveSection = LoadFrameHandle(hash, 0, i)
                              
                                if FrameGrid(GetHandleId(ActiveSection)).table == 0 then
                                    set FrameGrid(GetHandleId(ActiveSection)).table = table.create()
                                endif
                              
                                call BlzFrameSetPoint(PosFrame, FRAMEPOINT_TOPLEFT, LoadFrameHandle(hash, 0, i), FRAMEPOINT_BOTTOMLEFT, 0, 0)

                                // swap grid on and section off
                                call BlzFrameSetVisible(BossSections, false)
                                call BlzFrameSetVisible(BossGrid, true)
                              
                                // wait atleast 4 timer iterations before searching for a new section, .
                                set SectionFoundCount = 2
                            endif
                            set i = i - 1
                        endloop
                    endif
                else
                    set SectionFoundCount = SectionFoundCount - 1
                endif
            endif
        endmethod
      
        private static method evaluate2 takes nothing returns boolean
            local real sectionSizeX = SectionSizeX
            local real sectionSizeY = SectionSizeY
            local real xSize = 0.008 //dont go to low
            local real ySize = 0.008 //dont go to low
            local real yStart = ySize/2
            local real xStart = xSize/2
            local framehandle newButton
            local framehandle tooltipButton
            local real x = xStart
            local real y = yStart
            local Table ta = Table.create()
            loop
                exitwhen x == sectionSizeX
                loop
                    exitwhen y == sectionSizeY
                  
                    set newButton = BlzCreateFrameByType("FRAME", "", FrameGrid.BossGrid,"",0)
                    set tooltipButton = BlzCreateFrameByType("FRAME", "", FrameGrid.BossGrid,"",0)
                   //BlzFrameSetAbsPoint(newButton, FRAMEPOINT_CENTER, x, y)
                    call BlzFrameSetPoint(newButton, FRAMEPOINT_CENTER, FrameGrid.PosFrame, FRAMEPOINT_TOPLEFT, x, y)
                    call BlzFrameSetSize(newButton, xSize, ySize)
                    call BlzFrameSetTooltip(newButton, tooltipButton)
                    call BlzFrameSetEnable(newButton, false)
                    call BlzFrameSetEnable(tooltipButton, false)
                  
                    set ta.real[1] = x
                    set ta.real[2] = y
                  
                    set FrameGrid(GetHandleId(newButton)).table = ta
                    set FrameGrid(GetHandleId(tooltipButton)).table = ta
                  
                    call SaveFrameHandle(hash, 2, GridCount, newButton)
                    set GridCount = GridCount + 1
                    call SaveFrameHandle(hash, 3, GridCount2, tooltipButton)
                    set GridCount2 = GridCount2 + 1
                  
                    set y = y + ySize
                endloop
                set x = x + xSize
            endloop
            return false
        endmethod
      
        private static method evaluate takes nothing returns boolean
            local real sectionSizeX = SectionSizeX
            local real sectionSizeY = SectionSizeY
            local real x2 = 0.6 - sectionSizeX
            local real y2 = 0.6 - sectionSizeY
            local real x = 0
            local real y = 0
            local framehandle sectionFrame
            local framehandle tooltipSection
            local Table ta = Table.create()
          
            loop
                exitwhen x == x2
                loop
                    exitwhen y == y2
                  
                    set sectionFrame = BlzCreateFrameByType("FRAME", "", BossSections,"",0)
                    set tooltipSection = BlzCreateFrameByType("FRAME", "", BossSections,"",0)
                    call BlzFrameSetSize(sectionFrame, sectionSizeX, sectionSizeY)
                    //print(x, y)
                    //without +0.0001" the bottom row failed
                    call BlzFrameSetAbsPoint(sectionFrame, FRAMEPOINT_BOTTOMLEFT, x, y + 0.0001)
                    call BlzFrameSetEnable(sectionFrame, false)
                    call BlzFrameSetEnable(tooltipSection, false)
                    call BlzFrameSetTooltip(sectionFrame, tooltipSection)
                  
                    set ta.real[1] = x
                    set ta.real[2] = y
                  
                    set FrameGrid(GetHandleId(sectionFrame)).table = ta
                    set FrameGrid(GetHandleId(tooltipSection)).table = ta
                  
                    call SaveFrameHandle(hash, 0, SectionFrameCount, sectionFrame)
                    set SectionFrameCount = SectionFrameCount + 1
                    call SaveFrameHandle(hash, 1, SectionFrameCount2, tooltipSection)
                    set SectionFrameCount2 = SectionFrameCount2 + 1
                  
                    set y = y + sectionSizeY
                endloop
                set x = x + sectionSizeX
            endloop
      
            return false
        endmethod
      
        private static method onInit takes nothing returns nothing
            local trigger trig = CreateTrigger()
            local trigger trig2 = CreateTrigger()
            call TriggerAddCondition(trig, Filter(function thistype.evaluate))
            call TriggerAddCondition(trig2, Filter(function thistype.evaluate2))
          
            set hash = InitHashtable()
          
            set timer = CreateTimer()
            call TimerStart(timer, 0.01, true, function thistype.updateSimple)

            //the Grid Boss Frame its a BUTTON so it can have a higher Frame Level.
            //This Frame is used as on/off, when showing it the FrameGrid becomes active while it does nothing when Boss is disabled.
            set Boss = BlzCreateFrameByType("BUTTON", "FrameGridBoss", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0)
            set BossGrid = BlzCreateFrameByType("FRAME", "FrameGridBoss", Boss,"",0)
            set BossSections = BlzCreateFrameByType("FRAME", "FrameGridBoss", Boss,"",0)

            set PosFrame = BlzCreateFrameByType("FRAME", "FrameGridGridPos", Boss,"",0)
            call BlzFrameSetSize(PosFrame, 0.0001, 0.0001)
            call BlzFrameSetEnable(PosFrame, false)
          
            call TriggerEvaluate(trig)
            call TriggerEvaluate(trig2)
      
            call BlzFrameSetVisible(Boss, false)
            call BlzFrameSetVisible(BossSections, true)
            call BlzFrameSetVisible(BossGrid, false)
          
            call DestroyTrigger(trig)
            call DestroyTrigger(trig2)
            set trig = null
            set trig2 = null
            call BJDebugMsg("FrameGrid Init")
        endmethod
      
        static method show takes boolean flag, player p returns boolean
            if p == null or (GetLocalPlayer() == p) then
                call BlzFrameSetVisible(Boss, flag)
            endif
            return flag
        endmethod
    endstruct
endlibrary
JASS:
library MoveAbleFrame requires MouseUtils, FrameGrid

    struct MoveAbleFrame extends array
        private static boolean Enabled = true
        private static framehandle Frame
        private static framepointtype FramePoint
        private static trigger TriggerFrameEnter
        private static trigger TriggerFrameLeave
        private static trigger MouseClickTrigger
        private static trigger MouseReleaseTrigger
        private static framehandle PlayerHoveredFrame
      
        static method startMoving takes framehandle frame, framepointtype framePoint returns nothing
            set Frame = frame
            if framePoint == null then
                set framePoint = FRAMEPOINT_CENTER
            endif
            set FramePoint = framePoint
            call FrameGrid.show(true, null)
        endmethod
      
        static method moveFrame takes real x, real y, boolean finish returns nothing
            call BlzFrameClearAllPoints(Frame)
            call BlzFrameSetAbsPoint(Frame, FramePoint, x, y)
            if finish then
                call FrameGrid.show(false, null)
            endif
        endmethod
      
        static method enable takes player p, boolean flag returns boolean
            if GetLocalPlayer() == p then
                set Enabled = flag
            endif
            return Enabled
        endmethod
      
        static method setup takes framehandle frame returns nothing
            call BlzTriggerRegisterFrameEvent(TriggerFrameEnter, frame, FRAMEEVENT_MOUSE_ENTER) //enable the hover feature
            call BlzTriggerRegisterFrameEvent(TriggerFrameLeave, frame, FRAMEEVENT_MOUSE_LEAVE)
        endmethod
      
        private static method onMouseClick takes nothing returns boolean
            local player p = GetTriggerPlayer()
            if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
                if PlayerHoveredFrame != null then
                    //UI Edit Mode start moving that frame
                    if Enabled then
                        if GetLocalPlayer() == p then
                            call startMoving(PlayerHoveredFrame, null)
                            call BJDebugMsg(GetPlayerName(p) + " is moving " + BlzFrameGetName(PlayerHoveredFrame))
                           //disable the moving frame so it does not send mouse enter events, is more accurate to move and other frames are better respecected
                            call BlzFrameSetEnable(PlayerHoveredFrame, false)
                        endif
                    endif
                endif
            endif
            return false
        endmethod
      
        private static method onMouseRelease takes nothing returns boolean
             if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
                //reenable the movedFrame, if there is one
                if Frame != null then
                    call BlzFrameSetEnable(Frame, true)
                endif
                //UI Edit Mode start moving that frame
                //FrameGrid.show(false, GetTriggerPlayer())
            endif
            return false
        endmethod
      
        private static method enterFrame takes nothing returns nothing
            if GetLocalPlayer() == GetTriggerPlayer() then
                set PlayerHoveredFrame = BlzGetTriggerFrame()
                call BJDebugMsg("A player entered " + BlzFrameGetName(PlayerHoveredFrame))
            endif
        endmethod
      
        private static method leaveFrame takes nothing returns nothing
            if GetLocalPlayer() == GetTriggerPlayer() then
                set PlayerHoveredFrame = null
            endif
        endmethod
      
        private static method onInit takes nothing returns nothing
            local integer index = bj_MAX_PLAYER_SLOTS
          
            set TriggerFrameEnter = CreateTrigger()
            set TriggerFrameLeave = CreateTrigger()
            call TriggerAddAction(TriggerFrameEnter, function thistype.enterFrame)
            call TriggerAddAction(TriggerFrameLeave, function thistype.leaveFrame)
          
            loop
                set index = index - 1
                call TriggerRegisterPlayerEvent(MouseClickTrigger, Player(index), EVENT_PLAYER_MOUSE_DOWN)
                call TriggerRegisterPlayerEvent(MouseReleaseTrigger, Player(index), EVENT_PLAYER_MOUSE_UP)
                exitwhen index < 0
            endloop
          
            call TriggerAddAction(MouseClickTrigger, function thistype.onMouseClick)
            call TriggerAddAction(MouseReleaseTrigger, function thistype.onMouseRelease)
        endmethod
    endstruct
endlibrary
What could have gone wrong? Perhaps, I hit the op limit with the loops.
 
Do you have any plans of making a JASS version in the future?
Probably not.

Since the Mouse Cursor is a frame and one can now access it via
BlzFrameGetChild(frame, index)
, could you not get the screen position of the mouse that way?
I don't think so, based on my testing we did not get access to the Mouse Curosr-Frame itself, I think it is an ancient/parent of it because Scaling it also scales the visible mouse cursor texture. But the positon of an attached Frame does not change.
 

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,464
I think the MoveAbleFrame resource has enough of an overlap with the FrameGrid resource that they might both want to be part of the same script. They co-depend on each other as well, so one cannot currently exist without the other as-is. I think this is approvable if it is updated to use the updated initialization API and that the scripts are merged into one (so that it's easier to copy and paste).
 
Top