• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.
  • The Hive's 22nd Icon Contest: Creep Abilities is now concluded, time to vote for your favourite set of icons! Click here to vote!
  • ✅ The POLL for Hive's Texturing Contest #34 is OPEN! Vote for the TOP 3 SKINS! 🔗Click here to cast your vote!
  • ✅ The POLL for Hive's Techtree Contest #20 is OPEN! Vote for the TOP 3 FACTIONS! 🔗Click here to cast your vote!

[2.0.3] How to drag a frame with the mouse?

Level 3
Joined
Apr 19, 2022
Messages
18
Greetings, I can't figure out how to implement this:
We have a created frame, when the right mouse button is pressed on the frame it can be dragged, meaning the frame follows the mouse movement?
Preferably in JASS.
 
1) Convert mouse world coordinates (Point x,y,z) into screen pixel coordinates. Periodically set the frames position to these pixel coordinates.
OR
2) Create a grid of small, invisible frames that fill the screen. Then you can snap your other frames to them based on mouse enter events.

 
Last edited:
Which method is more efficient, runs smoother and faster, I assume Perfect Async mouse?
 
No problem, I rewrote the UI - Moveable Frame in vJass using a struct and a HashTable—it works the same as in Lua. However, whether in Lua or Jass, we don’t achieve smoothness with a 0.01 timing; the system looks more like a GIF.

Now I’ll try rewriting Perfect Async Mouse in Jass. Thanks.

I’ll also leave the rewritten system here in case it’s useful to anyone:

JASS:
library FrameGrid  requires MoveAbleFrame

struct structFrame
    framehandle array   GridFrames[4800]
    framehandle array   GridFrames2[4800]
    integer             LastFrame = 0
    timer               Timer  
    real                FramesEachCol
    hashtable Coords 
    integer             index = 0
    
    method setFrameCoords takes framehandle frame, real x, real y returns nothing
        call SaveReal(Coords, GetHandleId(frame), 0, x)
        call SaveReal(Coords, GetHandleId(frame), 1, y)
    endmethod
    
    method GetFrameCoordsX takes framehandle frame returns real
        return LoadReal(Coords, GetHandleId(frame), 0)
    endmethod
    
    method GetFrameCoordsY takes framehandle frame returns real
        return LoadReal(Coords, GetHandleId(frame), 1)
    endmethod

endstruct

globals
    structFrame FrameGrid
    framehandle         Boss = null
endglobals

/*function updateSimple takes nothing returns nothing
local framehandle value
local integer index = 0
    if BlzFrameIsVisible(FrameGrid.Boss) then
    call BJDebugMsg("updateSimple BlzFrameIsVisible")
        loop
            exitwhen index == FrameGrid.LastFrame + 1
            set value = FrameGrid.GridFrames2[index]
            if BlzFrameIsVisible(value) then
                call moveFrame(FrameGrid.GetFrameCoordsX(FrameGrid.GridFrames2[index]),FrameGrid.GetFrameCoordsY(FrameGrid.GridFrames2[index]), true)
                return
            endif
            set index = index + 1
        endloop
    endif
endfunction*/


function update2 takes nothing returns nothing
    local integer yA = FrameGrid.LastFrame 
    local integer yB = FrameGrid.LastFrame
    
    if BlzFrameIsVisible(Boss) then
        loop
        exitwhen (yA < 0 and yB >= 4800)
            if yA >= 0 then
                if BlzFrameIsVisible(FrameGrid.GridFrames2[yA]) then
                    set FrameGrid.LastFrame = yA
                    call BJDebugMsg("update: trying to move " + BlzFrameGetName(FrameGrid.GridFrames2[yA]))
                    call moveFrame(FrameGrid.GetFrameCoordsX(FrameGrid.GridFrames2[yA]),FrameGrid.GetFrameCoordsY(FrameGrid.GridFrames2[yA]), true)
                    return
                endif
                set yA = yA - 1
            endif
            if BlzFrameIsVisible(FrameGrid.GridFrames2[yB]) then
                set FrameGrid.LastFrame = yB
                call BJDebugMsg("update: trying to move" + BlzFrameGetName(FrameGrid.GridFrames2[yB]))
                call moveFrame(FrameGrid.GetFrameCoordsX(FrameGrid.GridFrames2[yB]),FrameGrid.GetFrameCoordsY(FrameGrid.GridFrames2[yB]), true)
                return
            else
                set yB = yB + 1
            endif
        endloop
    endif
endfunction

function HideBossFrame takes nothing returns nothing
    call BlzFrameSetVisible(Boss, false)
endfunction

globals
    framehandle newButton
    framehandle tooltipButton
endglobals

function onGameStart2 takes nothing returns nothing
    local real xSize = 0.01
    local real ySize = 0.01
    local real yStart = ySize/2
    local real xStart = xSize/2
    local real x = xStart
    local real y
    call PolledWait2(0.01)
    set FrameGrid = structFrame.create()
    set FrameGrid.Coords = InitHashtable()
    set FrameGrid.Timer = CreateTimer()
    call TimerStart(FrameGrid.Timer, 0.01, true, function update2)
    set Boss = BlzCreateFrameByType("BUTTON", "FrameGridBoss", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0)
    set FrameGrid.FramesEachCol = 0.6 / ySize

    loop
    exitwhen x>0.8
        set y = yStart
        loop
        exitwhen y>=0.6
            set newButton = BlzCreateFrameByType("FRAME", "FRAME" + I2S(FrameGrid.index), Boss,"",0)
            set tooltipButton = BlzCreateFrameByType("FRAME", "FRAME" + I2S(FrameGrid.index), Boss,"",0)
            call BlzFrameSetAbsPoint(newButton, FRAMEPOINT_CENTER, x, y)
            call BlzFrameSetSize(newButton, xSize, ySize)
            call BlzFrameSetTooltip(newButton, tooltipButton)
            call BlzFrameSetEnable(newButton, false)
            call BlzFrameSetEnable(tooltipButton, false)
            
            call FrameGrid.setFrameCoords(newButton,x,y)
            call FrameGrid.setFrameCoords(tooltipButton,x,y)
            set FrameGrid.GridFrames2[FrameGrid.index] = tooltipButton

            set FrameGrid.GridFrames[FrameGrid.index] = newButton
            
            set FrameGrid.index = FrameGrid.index + 1

        set y = y + ySize
        endloop
    set x = x + xSize
    endloop
    call BlzFrameSetVisible(Boss, false)
call onGameStart()
endfunction

endlibrary

JASS:
library MoveAbleFrame initializer onTriggerInit

struct structMoveAbleFrame
    boolean         Enabled = true
    
    framehandle     Frame = null
    framehandle     PlayerHoveredFrame
    framepointtype  FramePoint
    trigger         TriggerFrameEnter
    triggeraction   TriggerFrameEnterAction
    trigger         TriggerFrameLeave
    triggeraction   TriggerFrameLeaveAction
    trigger         MouseClickTrigger
    triggeraction   MouseClickTriggerAction
    trigger         MouseReleaseTrigger
    triggeraction   MouseReleaseTriggerAction
endstruct

globals
    structMoveAbleFrame MoveAbleFrame
endglobals

function enable takes player p, boolean flag returns boolean
    if GetLocalPlayer() == p then
        if flag == null then
            set MoveAbleFrame.Enabled = not MoveAbleFrame.Enabled
        else
            set MoveAbleFrame.Enabled = flag
        endif
    endif
    return MoveAbleFrame.Enabled
endfunction

function setup takes framehandle frame returns nothing
    //if not MoveAbleFrame[frame] then
        //MoveAbleFrame[frame] = true

        call BlzTriggerRegisterFrameEvent(MoveAbleFrame.TriggerFrameEnter, frame, FRAMEEVENT_MOUSE_ENTER)
        call BlzTriggerRegisterFrameEvent(MoveAbleFrame.TriggerFrameLeave , frame, FRAMEEVENT_MOUSE_LEAVE)
    //endif
endfunction

function show takes boolean flag, player p returns nothing
    if Boss == null then
        call BJDebugMsg("show: FrameGrid.Boss is null!")
    endif
    if BlzFrameIsVisible(Boss) then
        call BJDebugMsg("Boss true")
    else
        call BJDebugMsg("Boss false")
    endif
    if p == null or GetLocalPlayer() == p then
        call BlzFrameSetVisible(Boss, flag)
    endif
endfunction

function startMoving takes framehandle frame, framepointtype framePoint returns nothing
    //call BJDebugMsg("startMoving: called")
    set MoveAbleFrame.Frame = frame
    if framePoint == null then
       set framePoint = FRAMEPOINT_CENTER
    endif
    set MoveAbleFrame.FramePoint = framePoint
    call show(true, null)
    //call BJDebugMsg("startMoving: assigned " + BlzFrameGetName(MoveAbleFrame.Frame))
endfunction


function moveFrame takes real x, real y, boolean finish returns nothing

    call BJDebugMsg("moveFrame: called x=" + R2S(x) + " y=" + R2S(y))
    //call BJDebugMsg("moveFrame: moving " + BlzFrameGetName(MoveAbleFrame.Frame))
    call BlzFrameClearAllPoints(MoveAbleFrame.Frame)
    call BlzFrameSetAbsPoint(MoveAbleFrame.Frame, MoveAbleFrame.FramePoint, x, y)
    
    if finish then
        call show(true, null)
    endif
endfunction

function GetTriggerPlayerHoveredFrame takes nothing returns nothing
    if GetLocalPlayer() == GetTriggerPlayer() then
        call BJDebugMsg("Enter")
        set MoveAbleFrame.PlayerHoveredFrame = BlzGetTriggerFrame()
    endif
endfunction

function GetTriggerPlayerHoveredFrameNull takes nothing returns nothing
    if GetLocalPlayer() == GetTriggerPlayer() then
        call BJDebugMsg("Leave")
        set MoveAbleFrame.PlayerHoveredFrame = null
    endif
endfunction

function MouseClick takes nothing returns nothing
    local player p = GetTriggerPlayer()
    //call BJDebugMsg(GetPlayerName(p))
    if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
        //call BJDebugMsg("MouseClick: right click")
        if MoveAbleFrame.PlayerHoveredFrame != null then
            call BJDebugMsg("MouseClick: frame is not null: " + BlzFrameGetName(MoveAbleFrame.PlayerHoveredFrame))
            if MoveAbleFrame.Enabled then
                if GetLocalPlayer() == p then
                    call startMoving(MoveAbleFrame.PlayerHoveredFrame, FRAMEPOINT_CENTER)
                    call BlzFrameSetEnable(MoveAbleFrame.PlayerHoveredFrame, false)
                   //call BlzFrameSetVisible(Boss, flag)
                endif
            endif
        else
            call BJDebugMsg("MouseClick: PlayerHoveredFrame is null")
        endif
    endif
endfunction

function MouseRelease takes nothing returns nothing
    if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
        if MoveAbleFrame.Frame != null then
            call BlzFrameSetEnable(MoveAbleFrame.Frame, true)
        endif
        call show(false, GetTriggerPlayer())
    endif
endfunction

function PolledWait2 takes real time returns nothing
local timer t
local real R
    if time>0. then
        set t = CreateTimer()
        call TimerStart(t,time,false,null)
        loop
            set R=TimerGetRemaining(t)
            exitwhen R<=0.
                call TriggerSleepAction(R)
        endloop
        call DestroyTimer(t)
        set t=null
    endif
endfunction

function onTriggerInit takes nothing returns nothing
local integer playerIndex = 0
    call PolledWait2(0.01)
    set MoveAbleFrame = structMoveAbleFrame.create()
    
    set MoveAbleFrame.TriggerFrameEnter = CreateTrigger()
    set MoveAbleFrame.TriggerFrameEnterAction = TriggerAddAction(MoveAbleFrame.TriggerFrameEnter,function GetTriggerPlayerHoveredFrame)
    
    set MoveAbleFrame.TriggerFrameLeave = CreateTrigger()
    set MoveAbleFrame.TriggerFrameLeaveAction = TriggerAddAction(MoveAbleFrame.TriggerFrameLeave, function GetTriggerPlayerHoveredFrameNull)

    set MoveAbleFrame.MouseClickTrigger = CreateTrigger()
    set MoveAbleFrame.MouseClickTriggerAction = TriggerAddAction(MoveAbleFrame.MouseClickTrigger, function MouseClick)
    
    set MoveAbleFrame.MouseReleaseTrigger = CreateTrigger()
    set MoveAbleFrame.MouseReleaseTriggerAction = TriggerAddAction(MoveAbleFrame.MouseReleaseTrigger, function MouseRelease)

    loop
    exitwhen playerIndex == GetBJMaxPlayers()
        call TriggerRegisterPlayerEvent(MoveAbleFrame.MouseClickTrigger, Player(playerIndex), EVENT_PLAYER_MOUSE_DOWN)
        call TriggerRegisterPlayerEvent(MoveAbleFrame.MouseReleaseTrigger, Player(playerIndex), EVENT_PLAYER_MOUSE_UP)
        set playerIndex = playerIndex + 1
    endloop

    call ExecuteFunc("onGameStart2")
endfunction

endlibrary

JASS:
library Testb

private function click takes nothing returns nothing
    call BJDebugMsg("click " + BlzFrameGetName(BlzGetTriggerFrame()))
endfunction

private function enter takes nothing returns nothing
   // call BJDebugMsg("enter " + BlzFrameGetName(BlzGetTriggerFrame()))
endfunction

function onGameStart takes nothing returns nothing
    local framehandle gameUI = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
    local trigger t = CreateTrigger()
    local trigger t2 = CreateTrigger()
    local framehandle b
    call TriggerAddAction(t, function click)
    
    call TriggerAddAction(t2, function enter)
    
    set b =  BlzCreateFrameByType("GLUETEXTBUTTON", "b 1", gameUI, "ScriptDialogButton", 0)
    call BlzFrameSetAbsPoint(b, FRAMEPOINT_CENTER, 0.55, 0.4)
    call BlzFrameSetText(b, "b 1")

    call setup(b)

    call BlzTriggerRegisterFrameEvent(t, b, FRAMEEVENT_CONTROL_CLICK)
    call BlzTriggerRegisterFrameEvent(t2, b, FRAMEEVENT_MOUSE_ENTER)

    set b =  BlzCreateFrameByType("GLUETEXTBUTTON", "b 2", gameUI, "ScriptDialogButton", 0)
    call BlzFrameSetAbsPoint(b, FRAMEPOINT_CENTER, 0.55, 0.35)
    call BlzFrameSetText(b, "b 2")
    call setup(b)
    call BlzTriggerRegisterFrameEvent(t, b, FRAMEEVENT_CONTROL_CLICK)
    call BlzTriggerRegisterFrameEvent(t2, b, FRAMEEVENT_MOUSE_ENTER)
    set b =  BlzCreateFrameByType("GLUETEXTBUTTON", "b 3", gameUI, "ScriptDialogButton", 0)
    call BlzFrameSetAbsPoint(b, FRAMEPOINT_CENTER, 0.55, 0.45)
    call BlzFrameSetText(b, "b 3")
    call setup(b)
    call BlzTriggerRegisterFrameEvent(t, b, FRAMEEVENT_CONTROL_CLICK)
    call BlzTriggerRegisterFrameEvent(t2, b, FRAMEEVENT_MOUSE_ENTER)
    //call enable(GetLocalPlayer(),true)
    call BJDebugMsg(GetPlayerName(GetLocalPlayer()))
    call BJDebugMsg("onGameStart END")
endfunction

endlibrary
 
Back
Top