WoW:Making Draggable Frames: Difference between revisions

From AddOn Studio
Jump to navigation Jump to search
(fill out both options for moving a frame in both lua and xml)
m (Move page script moved page Making Draggable Frames to Making Draggable Frames without leaving a redirect)
 
(5 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{UIHowTo}}
{{wow/uihowto}}
Draggable frames can be moved by having the user hold down a mouse button over the frame, then move the mouse to reposition the frame. This HOWTO describes how to make a frame draggable.
Draggable frames can be moved by having the user hold down a mouse button over the frame, then move the mouse to reposition the frame. This HOWTO describes how to make a frame draggable.


Line 10: Line 10:
=== Using OnDragStart / OnDragStop ===
=== Using OnDragStart / OnDragStop ===
The code below creates a draggable Frame widget and uses the OnDrag widget handlers to initiate dragging. Note the use of movable and enableMouse attributes:
The code below creates a draggable Frame widget and uses the OnDrag widget handlers to initiate dragging. Note the use of movable and enableMouse attributes:
<Frame name="DragFrame1" enableMouse="true" movable="true">
  <Ui>
  <Frame name="DragFrame1" enableMouse="true" movable="true">
   <Scripts>
   <Scripts>
   <OnLoad>self:RegisterForDrag("LeftButton");</OnLoad>
   <OnLoad>self:RegisterForDrag("LeftButton");</OnLoad>
Line 18: Line 19:
   <nowiki><!-- Tags below add a visual element to the frame. --></nowiki>
   <nowiki><!-- Tags below add a visual element to the frame. --></nowiki>
   <Layers>
   <Layers>
   <Layer level="ARTWORK">
   &lt;Layer level="ARTWORK">
    <Texture setAllPoints="true">
<nowiki> </nowiki>  <Texture setAllPoints="true">
    <Color r="1.0" g="0.5" b="0.0" a="0.5" />
<nowiki> </nowiki>  <Color r="1.0" g="0.5" b="0.0" a="0.5" />
    </Texture>
<nowiki>  </Texture>
   </Layer>
   </Layer>
   </Layers>
   </Layers>
   <Size x="64" y="64" />
   </nowiki><Size x="64" y="64" />
  <Anchors><Anchor point="CENTER" relativeTo="UIParent"/></Anchors>
<nowiki> </nowiki><Anchors><Anchor point="CENTER" relativeTo="UIParent"/></Anchors>
  </Frame>
  </Frame>
</Ui>


Note the use of the OnLoad Script, In order to drag a frame it must register for drag via {{api|Frame RegisterForDrag|Frame:RegisterForDrag("button")}}.
Note the use of the OnLoad Script, In order to drag a frame it must register for drag via {{api|Frame RegisterForDrag|Frame:RegisterForDrag("button")}}. Above code edited to include the <Ui> </Ui> tags as it
is .xml and won't work without this.


=== Using OnMouseUp/OnMouseDown ===
=== Using OnMouseUp/OnMouseDown ===
Line 65: Line 68:
   <TitleRegion>
   <TitleRegion>
   <Size x="100" y="20"/>
   <Size x="100" y="20"/>
   <Anchors><Anchor point="TOP"></Anchors>
   <Anchors><Anchor point="TOP"/></Anchors>
   <TitleRegion>
   </TitleRegion>
   <nowiki><!-- Tags below add a visual element to the frame. --></nowiki>
   <nowiki><!-- Tags below add a visual element to the frame. --></nowiki>
   <Layers>
   <Layers>
   <Layer level="ARTWORK">
   &lt;Layer level="ARTWORK">
    <Texture setAllPoints="true">
<nowiki> </nowiki>  <Texture setAllPoints="true">
    <Color r="1.0" g="0.5" b="0.0" a="0.5" />
<nowiki> </nowiki>  <Color r="1.0" g="0.5" b="0.0" a="0.5" />
    </Texture>
<nowiki>  </Texture>
  </Layer>
    </Layer>
  </Layers>
  </Layers>
  <Anchors><Anchor point="CENTER" relativeTo="UIParent"/></Anchors>
  </nowiki><Anchors><Anchor point="CENTER" relativeTo="UIParent"/></Anchors>
  </Frame>
  </Frame>


Line 92: Line 95:
  tex:SetAllPoints();
  tex:SetAllPoints();
  tex:SetTexture(1.0, 0.5, 0); tex:SetAlpha(0.5);
  tex:SetTexture(1.0, 0.5, 0); tex:SetAlpha(0.5);


=== Using OnMouseDown / OnMouseUp ===
=== Using OnMouseDown / OnMouseUp ===
Line 100: Line 101:
  frame:SetMovable(true)
  frame:SetMovable(true)
  frame:EnableMouse(true)
  frame:EnableMouse(true)
  frame:SetScript("OnMouseDown", function(self)
  frame:SetScript("OnMouseDown", function(self, button)
   if button == "LeftButton" and not self.isMoving then
   if button == "LeftButton" and not self.isMoving then
     self:StartMoving();
     self:StartMoving();
Line 106: Line 107:
   end
   end
  end)
  end)
  frame:SetScript("OnMouseUp", function(self)
  frame:SetScript("OnMouseUp", function(self, button)
   if button == "LeftButton" and self.isMoving then
   if button == "LeftButton" and self.isMoving then
     self:StopMovingOrSizing();
     self:StopMovingOrSizing();
Line 123: Line 124:
  tex:SetAllPoints();
  tex:SetAllPoints();
  tex:SetTexture(1.0, 0.5, 0); tex:SetAlpha(0.5);
  tex:SetTexture(1.0, 0.5, 0); tex:SetAlpha(0.5);


==General Notes==
==General Notes==

Latest revision as of 04:48, 15 August 2023

HOWTOs

Draggable frames can be moved by having the user hold down a mouse button over the frame, then move the mouse to reposition the frame. This HOWTO describes how to make a frame draggable.

Summary

To initiate dragging of a frame, call Frame:StartMoving(); to stop, call Frame:StopMovingOrSizing(). The frame must be flagged as movable (either through the movable attribute in its XML declaration or using Frame:SetMovable(isMovable).

There are generally 2 methods that are used for moving a frame, by Dragging the frame (OnDragStart & OnDragStop Handlers) or Clicking the frame (OnMouseDown & OnMouseUp Handlers). Note: that to receive mouse events (including dragging), the frame must be mouse enabled (either through the enableMouse attribute in its XML declaration or using Frame:EnableMouse(isEnabled)); buttons are mouse-enabled by default.

Using XML

Using OnDragStart / OnDragStop

The code below creates a draggable Frame widget and uses the OnDrag widget handlers to initiate dragging. Note the use of movable and enableMouse attributes:

 <Ui>
 <Frame name="DragFrame1" enableMouse="true" movable="true">
 <Scripts>
  <OnLoad>self:RegisterForDrag("LeftButton");</OnLoad>
  <OnDragStart>self:StartMoving();</OnDragStart>
  <OnDragStop>self:StopMovingOrSizing();</OnDragStop>
 </Scripts>
 <!-- Tags below add a visual element to the frame. -->
 <Layers>
  <Layer level="ARTWORK">
   <Texture setAllPoints="true">
    <Color r="1.0" g="0.5" b="0.0" a="0.5" />
   </Texture>
   </Layer>
  </Layers>
  <Size x="64" y="64" />
 <Anchors><Anchor point="CENTER" relativeTo="UIParent"/></Anchors>
</Frame>
</Ui>

Note the use of the OnLoad Script, In order to drag a frame it must register for drag via Frame:RegisterForDrag("button"). Above code edited to include the <Ui> </Ui> tags as it is .xml and won't work without this.

Using OnMouseUp/OnMouseDown

While OnDrag* handlers typically require the mouse button to be held down for a small amount of time prior to enabling the mouse behavior, making them well suited for dragging widgets that normally respond to clicks. However, if the frame you wish to make draggable is not normally a button, you can use OnMouseUp/OnMouseDown to provide a more responsive experience.

The following snippet illustrates this concept, and should replace the <Scripts> block above:

<Scripts>
 <OnMouseDown>
  if button == "LeftButton" and not self.isMoving then
   self:StartMoving();
   self.isMoving = true;
  end
 </OnMouseDown>
 <OnMouseUp>
  if button == "LeftButton" and self.isMoving then
   self:StopMovingOrSizing();
   self.isMoving = false;
  end
 </OnMouseUp>
 <OnHide>
  if ( this.isMoving ) then
   this:StopMovingOrSizing();
   this.isMoving = false;
  end
 </OnHide>
</Scripts>

Note: this also adds a frame.isLocked boolean field to control whether the frame can be dragged or not. There's generally no limit to the amount of conditional logic you can insert prior to :StartMoving() -- for instance, requiring the user to hold down some modifier button is a possible alternative.

Using TitleRegion

Frames can have a TitleRegion object that handles dragging automatically -- as long as the mouse is held down within the TitleRegion, it'll allow the frame to be dragged.

The frame created below will be draggable by clicking on its top 20 pixels:

<Frame enableMouse="true">
 <Size x="100" y="100"/>
 <TitleRegion>
  <Size x="100" y="20"/>
  <Anchors><Anchor point="TOP"/></Anchors>
 </TitleRegion>
 <!-- Tags below add a visual element to the frame. -->
 <Layers>
  <Layer level="ARTWORK">
   <Texture setAllPoints="true">
    <Color r="1.0" g="0.5" b="0.0" a="0.5" />
   </Texture>
    </Layer>
   </Layers>
   <Anchors><Anchor point="CENTER" relativeTo="UIParent"/></Anchors>
</Frame>

Using Lua

Using OnDragStart OnDragStop

The code sample below illustrates the use of the Widget API to achieve the same results as the XML above:

local frame = CreateFrame("Frame", "DragFrame2", UIParent)
frame:SetMovable(true)
frame:EnableMouse(true)
frame:RegisterForDrag("LeftButton")
frame:SetScript("OnDragStart", frame.StartMoving)
frame:SetScript("OnDragStop", frame.StopMovingOrSizing)
-- The code below makes the frame visible, and is not necessary to enable dragging.
frame:SetPoint("CENTER"); frame:SetWidth(64); frame:SetHeight(64);
local tex = frame:CreateTexture("ARTWORK");
tex:SetAllPoints();
tex:SetTexture(1.0, 0.5, 0); tex:SetAlpha(0.5);

Using OnMouseDown / OnMouseUp

The code sample below illustrates the use of the Widget API to achieve the same results as the XML above:

local frame = CreateFrame("Frame", "DragFrame2", UIParent)
frame:SetMovable(true)
frame:EnableMouse(true)
frame:SetScript("OnMouseDown", function(self, button)
  if button == "LeftButton" and not self.isMoving then
   self:StartMoving();
   self.isMoving = true;
  end
end)
frame:SetScript("OnMouseUp", function(self, button)
  if button == "LeftButton" and self.isMoving then
   self:StopMovingOrSizing();
   self.isMoving = false;
  end
end)
frame:SetScript("OnHide", function(self)
  if ( self.isMoving ) then
   self:StopMovingOrSizing();
   self.isMoving = false;
  end
end)
-- The code below makes the frame visible, and is not necessary to enable dragging.
frame:SetPoint("CENTER"); frame:SetWidth(64); frame:SetHeight(64);
local tex = frame:CreateTexture("ARTWORK");
tex:SetAllPoints();
tex:SetTexture(1.0, 0.5, 0); tex:SetAlpha(0.5);

General Notes

The use of the OnHide Handler is not entirely necessary. However it is a good idea if your frames are being Hidden or Shown by running code and not the User.

The use of full functions is also not required in lua:

frame:SetScript("OnDragStart" frame.StartMoving)
frame:SetScript("OnDragStop" frame.StopMovingOrSizing)
frame:SetScript("OnMouseDown" frame.StartMoving)
frame:SetScript("OnMouseUp" frame.StopMovingOrSizing)


In XML all that is required is just the function:

<OnDragStart>self:StartMoving();</OnDragStart>
<OnDragStop>self:StopMovingOrSizing();</OnDragStop>
<OnMouseDown>self:StartMoving();</OnMouseDown>
<OnMouseUp>self:StopMovingOrSizing();</OnMouseUp>