Draggable Frame

This bundle is marked as pending. It has not been reviewed by a staff member yet.
This simple function allows you to drag any frame.

Features
  • Can drag the frame from any section of the frame
  • The mouse remains on that same section while dragging the frame
  • Drag frame by holding the mouse button down
  • Stop dragging the frame by letting go of the mouse button

W3CE

UjAPI

Reforged

Changelog

NOTE: This edition only works on Warcraft III: Community Edition since it uses the new native functions introduced by the tool.

WurstScript

Lua

JASS

TypeScript

Wurst:
package DraggableFrame

import FramehandleNames
import ClosureFrames
import ClosureTimers

framehandle array clicked_frame

public function framehandle.enableDrag()
    createFrame(FramehandleTypeNames.gluetextbutton, "", this, "", 0)
    ..setAllPoints(this)
    ..onMouseDown() ->
        let p = EventData.getTriggerPlayer()
        EventData.getTriggerFrame().unfocus(p)
        let id = p.getId()

        clicked_frame[id] = this

        var mouseX = CeGetFrameX(getOriginFrame(ORIGIN_FRAME_MOUSE_CURSOR))
        var mouseY = CeGetFrameY(getOriginFrame(ORIGIN_FRAME_MOUSE_CURSOR))

        let delta_x = mouseX - CeGetFrameX(this)
        let delta_y = mouseY - CeGetFrameY(this)

        doPeriodically(ANIMATION_PERIOD) (CallbackPeriodic cb) ->
            if clicked_frame[id] != null
                mouseX = CeGetFrameX(getOriginFrame(ORIGIN_FRAME_MOUSE_CURSOR))
                mouseY = CeGetFrameY(getOriginFrame(ORIGIN_FRAME_MOUSE_CURSOR))
                let x = mouseX - delta_x
                let y = mouseY - delta_y
                if localPlayer == p
                    this..clearAllPoints()..setAbsPoint(FRAMEPOINT_CENTER, x, y)
            else
                destroy cb
init
    let trg = CreateTrigger()..addAction() ->
        clicked_frame[EventData.getTriggerPlayer().getId()] = null
    for i = 0 to bj_MAX_PLAYER_SLOTS - 1
        trg.registerPlayerEvent(players[i], EVENT_PLAYER_MOUSE_UP)
Wurst:
package Test

import DraggableFrame
import FramehandleNames
import Textures

init
    createFrame(FramehandleTypeNames.backdrop, "", getFrame("ConsoleUIBackdrop"), "", 0)
    ..setSize(0.1, 0.1)
    ..setAbsPoint(FRAMEPOINT_CENTER, SCREEN_CENTER)
    ..enableDrag()
    ..setTexture(Textures.black321, 0, false)
Lua:
do
    local clicked_frame
    local parent_frame
    local trg

    ---@param frame framehandle
    function BlzFrameEnableDrag(frame)
        local dummy = BlzCreateFrameByType("GLUETEXTBUTTON", "", frame, "", 0)
        BlzFrameSetAllPoints(dummy, frame)
        BlzTriggerRegisterFrameEvent(trg, dummy, FRAMEEVENT_MOUSE_DOWN)
        parent_frame[dummy] = frame
    end

    local function init()
        clicked_frame = {}
        parent_frame = {}
        trg = CreateTrigger()

        TriggerAddCondition(trg, Filter(function()
            local p = GetTriggerPlayer()
            if clicked_frame[p] == nil then
                clicked_frame[p] = parent_frame[BlzGetTriggerFrame()]

                local delta_x = CeGetFrameX(BlzGetOriginFrame(ORIGIN_FRAME_MOUSE_CURSOR, 0)) - CeGetFrameX(clicked_frame[p])
                local delta_y = CeGetFrameY(BlzGetOriginFrame(ORIGIN_FRAME_MOUSE_CURSOR, 0)) - CeGetFrameY(clicked_frame[p])

                TimerStart(CreateTimer(), 1/30, true, function()
                    if clicked_frame[p] ~= nil then
                        local x = CeGetFrameX(BlzGetOriginFrame(ORIGIN_FRAME_MOUSE_CURSOR, 0)) - delta_x
                        local y = CeGetFrameY(BlzGetOriginFrame(ORIGIN_FRAME_MOUSE_CURSOR, 0)) - delta_y

                        if GetLocalPlayer() == p then
                            BlzFrameClearAllPoints(clicked_frame[p])
                            BlzFrameSetAbsPoint(clicked_frame[p], FRAMEPOINT_CENTER, x, y)
                        end
                    else
                        DestroyTimer(GetExpiredTimer())
                    end
                end)
            end
        end))

        local trig = CreateTrigger()
        for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
            TriggerRegisterPlayerEvent(trig, Player(i), EVENT_PLAYER_MOUSE_UP)
        end
        TriggerAddCondition(trig, Filter(function()
            clicked_frame[GetTriggerPlayer()] = nil
        end))
    end

    if OnInit then
        OnInit.final(init)
    else
        local real = MarkGameStarted
        function MarkGameStarted()
            real()
            init()
        end
    end

end
Not feasible because the game lags too much while dragging a frame.
Coming Soon!
NOTE: This edition only works with UjAPI since it uses the new native functions introduced by the tool.

WurstScript

Lua

JASS

AngelScript

Wurst:
package DraggableFrame

import FramehandleNames
import ClosureFrames
import ClosureTimers

framehandle array clicked_frame

public function framehandle.enableDrag()
    createFrame(FramehandleTypeNames.gluetextbutton, "", this, "", 0)
    ..setAllPoints(this)
    ..onMouseDown() ->
        let p = EventData.getTriggerPlayer()
        EventData.getTriggerFrame().unfocus(p)
        let id = p.getId()

        clicked_frame[id] = this

        var mouseX = GetMouseScreenRelativeX()
        var mouseY = GetMouseScreenRelativeY()

        let delta_x = mouseX - GetFrameScreenX(this)
        let delta_y = mouseY - GetFrameScreenY(this)

        doPeriodically(ANIMATION_PERIOD) (CallbackPeriodic cb) ->
            if clicked_frame[id] != null
                mouseX = GetMouseScreenRelativeX()
                mouseY = GetMouseScreenRelativeY()
                let x = mouseX - delta_x
                let y = mouseY - delta_y
                if localPlayer == p
                    this..clearAllPoints()..setAbsPoint(FRAMEPOINT_CENTER, x, y)
            else
                destroy cb
init
    let trg = CreateTrigger()..addAction() ->
        clicked_frame[EventData.getTriggerPlayer().getId()] = null
    for i = 0 to bj_MAX_PLAYER_SLOTS - 1
        trg.registerPlayerEvent(players[i], EVENT_PLAYER_MOUSE_UP)
Pure Lua is not working at the moment with this tool.
JASS:
library DraggableFrame initializer Init

    globals
        private framehandle array clicked_frame
        private real array delta_x
        private real array delta_y
        private hashtable hash = InitHashtable()
    endglobals

    private function OnExpired takes nothing returns nothing
        local integer id = LoadInteger(hash, 0, GetHandleId(GetExpiredTimer()))
        local real x
        local real y

        if clicked_frame[id] != null then
            set x = GetMouseScreenRelativeX() - delta_x[id]
            set y = GetMouseScreenRelativeY() - delta_y[id]

            call BlzFrameClearAllPoints(clicked_frame[id])
            call BlzFrameSetAbsPoint(clicked_frame[id], FRAMEPOINT_CENTER, x, y)
        else
            call RemoveSavedInteger(hash, 0, GetHandleId(GetExpiredTimer()))
            call DestroyTimer(GetExpiredTimer())
        endif
    endfunction

    private function OnMouseDown takes nothing returns nothing
        local integer id = GetPlayerId(GetTriggerPlayer())
        local timer t

        if clicked_frame[id] == null then
            set t = CreateTimer()

            set clicked_frame[id] = BlzFrameGetParent(BlzGetTriggerFrame())
            set delta_x[id] = GetMouseScreenRelativeX() - GetFrameScreenX(clicked_frame[id])
            set delta_y[id] = GetMouseScreenRelativeY() - GetFrameScreenY(clicked_frame[id])

            call TimerStart(t, 1/120, true, function OnExpired)

            call SaveInteger(hash, 0, GetHandleId(t), id)
        endif
    endfunction

    function BlzFrameEnableDrag takes framehandle frame returns nothing
        local framehandle dummy = BlzCreateFrameByType("GLUETEXTBUTTON", "", frame, "", 0)
        local trigger trig = CreateTrigger()

        call BlzFrameSetAllPoints(dummy, frame)

        call BlzTriggerRegisterFrameEvent(trig, dummy, FRAMEEVENT_MOUSE_DOWN)
        call TriggerAddCondition(trig, Filter(function OnMouseDown))
    endfunction

    private function OnMouseUp takes nothing returns nothing
        set clicked_frame[GetPlayerId(GetTriggerPlayer())] = null
    endfunction

    private function Init takes nothing returns nothing
        local trigger trig = CreateTrigger()
        local integer i = 0
        loop
            exitwhen i == bj_MAX_PLAYER_SLOTS
            call TriggerRegisterPlayerEvent(trig, Player(i), EVENT_PLAYER_MOUSE_UP)
            set i = i + 1
        endloop
        call TriggerAddCondition(trig, Filter(function OnMouseUp))
    endfunction

endlibrary
Coming Soon!
Coming Soon!

Current


  • Added Lua version for W3CE edition
  • Added WurstScript and JASS versions for UjAPI

Contents

Drag Frame Test (Map)

While we allow Wurst resources, a Wurst resource that only works on a custom version of Warcraft 3 is a hard ask. We also have no moderator who can review this.

The same functionality can be achieved on the live version using either World2Screen Transform or the Mouse Tracker, so you could make a version for live that way.
 
Level 19
Joined
Oct 17, 2012
Messages
859
Who doesn't have fun dragging Nietzsche abyss squares around?
It's all fun and games until the abyss starts dragging you around instead. Nietzsche forgot to mention that part!


While we allow Wurst resources, a Wurst resource that only works on a custom version of Warcraft 3 is a hard ask. We also have no moderator who can review this.

The same functionality can be achieved on the live version using either World2Screen Transform or the Mouse Tracker, so you could make a version for live that way.
For the live version, getting the center point of a frame is not so easy. It will require substantial work on the user side.

I can hook into BlzFrameSetAbsPoint and BlzFrameSetPoint and calculate the center point.

It is easier to calculate the center point if the user is using BlzFrameSetAbsPoint. There is one prerequisite, however. The user has to set the width and height of the frame. This isn't necessary if the user is using the FRAMEPOINT_CENTER to position the frame.

If BlzFrameSetPoint is used, I will have to check the position of the frame against the relative one, whose position may be set via a relative one as well. And the list goes on.
 
Last edited:
Top