Thread Tools Display Modes
11-04-10, 10:22 AM   #1
Chamenas
Premium Member
 
Chamenas's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 14
Odd Issue with Re-Positioning via Points

The Problem:
The best way to illustrate this problem is with some images. I'm going to link them rather than post them in here due to their size.

The first image shows the default setup of my Rune bar for the AddOn. As you can see, there are 3 rows with 2 columns:
3 Rows - 2 Columns

Next, as you can see, I'm working on offering alternative layout arrangements, including allowing users to simply move the Runes to their own individual locations. However, before I take that last step, I'd like to offer users the ability to have some "stock" layout arrangements that they can choose quickly rather than have to setup manually. You can see those here:
Layout Options

For the purposes of this we'll choose the 2 rows and 3 columns option, but it should be noted that this problem happens across all options. Now, as you can see in the next two pictures, we've chosen 2 rows and 3 columns, but it's not quite setup like that. Rather, runes 2 and 3 seem to be at the bottom-right corner of rune 1. Runes 4 and 5 seem to be at the bottom-right corner of 2 and 3 and rune 6 is at the bottom right corner of runes 4 and 5:
2-3 Options
2 Rows - 3 Columns (broken)

This would lead one to believe that something must have happened, somewhere in my code, where I set them to topleft - bottomright, correct? Except, if we do a /reload, as I've done for this final image, everything is setup correctly:
2 Rows - 3 Columns (fixed)

The logical assertion that follows is that perhaps there's something different between the code that initially lays out my runes and the code that dynamically shifts them, but that's not the case at all, here are the two:

The Code:
The bolded sections are relevant to the placement of the frames:

Initial Setup:
Code:
local function SetRuneFrames()
	local img = IMG..PowerBarsDB.PowSet.PowIMG;
	if not PowerBars.Runes then
		PowerBars.Runes = {}
		local Runes = PowerBars.Runes;
		local Frame = PowerBarsDB.PowSet.Frame[1];
		local Base = PowerBars.Base.Resource.Frame;
		for i=1,6 do
			Runes[i] = {};
			local RuneF = PowerBarsDB.PowSet.Frame[i+2];
			local Rune = Runes[i];
			Rune.Frame = CreateFrame("FRAME", nil, Base);
			Rune.Frame:SetSize(RuneF.Width, RuneF.Height);
			if i == 1 then
				Rune.Frame:SetPoint(RuneF.Point);
			elseif i % 2 == 0 then
				Rune.Frame:SetPoint(RuneF.Point, Runes[i-1].Frame, RuneF.RelativePoint);
			else
				if PowerBarsDB.Options.DEATHKNIGHT.Layout == 3 or PowerBarsDB.Options.DEATHKNIGHT.Layout == 4 then
					Rune.Frame:SetPoint(RuneF.Point, Runes[i-1].Frame, RuneF.RelativePoint);
				else
					Rune.Frame:SetPoint(RuneF.Point, Runes[i-2].Frame, RuneF.RelativePoint);
				end
			end
			Rune.Frame.Texture = Rune.Frame:CreateTexture(nil, "BACKGROUND");
			local Texture = Rune.Frame.Texture
			Texture:SetAllPoints(Rune.Frame);
			local currRune = GetRuneType(i) or i;
			Texture:SetTexture(img..currRune);
			Rune.Frame.Cooldown = CreateFrame("Cooldown", nil, Rune.Frame);
			local Cooldown = Rune.Frame.Cooldown;
			Cooldown:SetAllPoints(Rune.Frame);
			Cooldown:SetFrameStrata("LOW");
			if IsAddOnLoaded("OmniCC") then
				PowerBars.Class.DEATHKNIGHT.Check.OmniCC:Enable();
				if PowerBarsDB.Options.DEATHKNIGHT.OmniCC == 1 then
					Cooldown.noCooldownCount = false;
				else
					Cooldown.noCooldownCount = true;
				end
			else
				PowerBars.Class.DEATHKNIGHT.Check.OmniCC:Disable();
			end
			Cooldown.currCD = 0;
			Cooldown.Frame = CreateFrame("FRAME", nil, Rune.Frame);
			local CDFrame = Cooldown.Frame;
			CDFrame:SetAllPoints(Rune.Frame);
			CDFrame:SetFrameStrata("MEDIUM");
			CDFrame.Text = PowerBars:CreateFont(CDFrame, Cooldown.currCD, "DEFAULT", Cooldown:GetWidth()/2, 0, 0, "CENTER", {255,255,0,1}, "DRAWINGLAYER", "OUTLINE");
			local Text = CDFrame.Text;
			Text:SetAllPoints(CDFrame);
			CDFrame:Hide();
			Rune.Timer = RuneTimer(i);
		end
	end
end
This next bit of code is actually two bits of code split up. The first is a function I use to position and place runes. The second is the bit of code which executes the various dropdown items, in that function you will see the values:

Dynamic Placement after Setup:
Code:
local function doRuneFrames()
	local Runes = PowerBars.Runes;
	local Base = PowerBars.Base.Resource.Frame;
	local Frame = PowerBarsDB.PowSet.Frame[1];
	for i=1,6 do
		local Rune = Runes[i];
		local RuneF = PowerBarsDB.PowSet.Frame[i+2];
		Rune.Frame:SetSize(RuneF.Width, RuneF.Height);
		if i == 1 then
			Rune.Frame:SetPoint(RuneF.Point);
		elseif i % 2 == 0 then
			Rune.Frame:SetPoint(RuneF.Point, Runes[i-1].Frame, RuneF.RelativePoint);
		else
			if PowerBarsDB.Options.DEATHKNIGHT.Layout == 3 or PowerBarsDB.Options.DEATHKNIGHT.Layout == 4 then
					Rune.Frame:SetPoint(RuneF.Point, Runes[i-1].Frame, RuneF.RelativePoint);
			else
				Rune.Frame:SetPoint(RuneF.Point, Runes[i-2].Frame, RuneF.RelativePoint);
			end
		end
	end
end

function DKLayout.SelectLayout(self, arg1)
		local Frame = PowerBarsDB.PowSet.Frame;
		local Settings = PowerBars.Defaults.DEATHKNIGHT.Settings[1];
		UIDropDownMenu_SetSelectedID(DKLayout, self:GetID());
		if arg1 == "3-2" then
			PowerBarsDB.Options.DEATHKNIGHT.Layout = 1;
			Frame[1].Width = Settings.WIDTH;
			Frame[1].Height = Settings.HEIGHT;
			PowerBars.Base.Resource.Frame:SetSize(Frame[1].Width, Frame[1].Height);
			local Runes = PowerBars.Runes;
			for i=1,6 do
				local RuneF = PowerBarsDB.PowSet.Frame[i+2];
				if i == 1 then
					RuneF.Point = "TOPLEFT";
				elseif i % 2 == 0 then
					RuneF.Point = "LEFT";
					RuneF.RelativePoint = "RIGHT";
				else
					RuneF.Point = "TOP";
					RuneF.RelativePoint = "BOTTOM";
				end
			end
			doRuneFrames();
		elseif arg1 == "2-3" then
			PowerBarsDB.Options.DEATHKNIGHT.Layout = 2;
			Frame[1].Width = Settings.HEIGHT;
			Frame[1].Height = Settings.WIDTH;
			PowerBars.Base.Resource.Frame:SetSize(Frame[1].Width, Frame[1].Height);
			local Runes = PowerBars.Runes;
			for i=1,6 do
				local RuneF = PowerBarsDB.PowSet.Frame[i+2];
				if i == 1 then
					RuneF.Point = "TOPLEFT";
				elseif i % 2 == 0 then
					RuneF.Point = "TOP";
					RuneF.RelativePoint = "BOTTOM";
				else
					RuneF.Point = "LEFT";
					RuneF.RelativePoint = "RIGHT";
				end
			end
			doRuneFrames();
		elseif arg1 == "1-6" then
			PowerBarsDB.Options.DEATHKNIGHT.Layout = 3;
			Frame[1].Width = 240;
			Frame[1].Height = 40;
			PowerBars.Base.Resource.Frame:SetSize(Frame[1].Width, Frame[1].Height);
			local Runes = PowerBars.Runes;
			for i=1,6 do
				local RuneF = PowerBarsDB.PowSet.Frame[i+2];
				local Rune = Runes[i];
				if i == 1 then
					RuneF.Point = "TOPLEFT";
				elseif i % 2 == 0 then
					RuneF.Point = "LEFT";
					RuneF.RelativePoint = "RIGHT";
				else
					RuneF.Point = "LEFT";
					RuneF.RelativePoint = "RIGHT";
				end
			end
			doRuneFrames();
		elseif arg1 == "6-1" then
			PowerBarsDB.Options.DEATHKNIGHT.Layout = 4;
			Frame[1].Width = 40;
			Frame[1].Height = 240;
			PowerBars.Base.Resource.Frame:SetSize(Frame[1].Width, Frame[1].Height);
			local Runes = PowerBars.Runes;
			for i=1,6 do
				local RuneF = PowerBarsDB.PowSet.Frame[i+2];
				local Rune = Runes[i];
				if i == 1 then
					RuneF.Point = "TOPLEFT";
				elseif i % 2 == 0 then
					RuneF.Point = "TOP";
					RuneF.RelativePoint = "BOTTOM";
				else
					RuneF.Point = "TOP";
					RuneF.RelativePoint = "BOTTOM";
				end 
			end
			doRuneFrames();
		elseif arg1 == "unlock" then
			print("Unlock not yet functional.");
			--PowerBarsDB.Options.DEATHKNIGHT.Layout = 5;
		end
	end
You'll notice that the bolded sections are EXACTLY the same. The value given to each rune for Point and RelativePoint is a savedvariableperchar which stores information on the size and placement of the individual runes if the character is a Death Knight. In the initial bit of code, it simply grabs this from the information in the file, aka, whatever it was before the last reload or log-off. In the second bit of code it does this while the game is running, grabbing the current values which may be the same as the initial values, or, since it's only generally called when something changes, usually there's some difference to the values.

However, as explained above are correctly saved. When a /reload is done, all of the runes are set in the proper position.

Other Things of Note:
It should be noted that I had this problem once before in my code. Initially, I allowed users to move and resize the base frame for my addon's display of resources. Because they might end up placing or resizing them in funky ways, I also added a "reset" button which would allow them to restore the initial size and placement values. Despite the initial size and placement values being correctly stored and set however, the frames would often resize, but not to the proper size, and not be placed in the proper position. If one did a /reload, then everything would be sized and placed as expected.

In an attempt to fix the situation I eventually used setmovable and setresizeable in the code for the resetting, setting them to true in the beginning and then resetting them to false after. However, despite making the frames "movable" and "resizable" I still had the issue. It was eventually solved by changing the "resize" option to a "scale" option as the game seemed to have no issues setting it back to its correct scale and position.

But, whereas the game had no issue setting back to the correct position before, unless the size was different, in this instance it seems that it does. I have not personally tried using setmovable in this specific instance yet, but I will try (even though the frames are clearly moving, just not to the proper places). It was also suggested by me to try and have the frames reset to a central location and use offsets to position them. I will try this as well, though, if it works, it still speaks to issues with dynamically anchoring off of set points.

Hopefully someone will be able to help as I'd prefer to keep the setup that I have, it SHOULD be functional, but isn't.
  Reply With Quote
11-04-10, 10:30 AM   #2
Chamenas
Premium Member
 
Chamenas's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2010
Posts: 14
jnwhiteh is the man! (or woman). I didn't use ClearAllPoints() (which explains why they didn't move properly when they did in my old example since I used the function in the old example).

It still doesn't explain why the old examples wouldn't resize properly, but that information isn't necessarily needed at the moment. It could be needed in the future though, so if anyone has any thoughts on it, please do share.
  Reply With Quote
11-04-10, 08:18 PM   #3
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Yeah, frames can take multiple SetPoint() calls. This can also impact their size, and is usually used this way as such.

For example, if you want a texture behind your chat frame, but want to take into account any size the chat frame may be for all of your characters....
lua Code:
  1. local f = CreateFrame("Frame")
  2. local t = f:CreateTexture()
  3.     t:SetAllPoints(f)
  4.     t:SetTexture("path\\to\\my\\texture")
  5. f:SetPoint("TOPLEFT", ChatFrame1, "TOPLEFT", -3, 3)
  6. f:SetPoint("BOTTOMRIGHT, ChatFrame1, "BOTTOMRIGHT", 3, -3)

This will anchor the frame to the top left of the chat frame (with a padding of 3) and to the bottom right of the chat frame (with the same padding of 3). It doesn't matter how big the chat frame is, the frame/texture will always be the correct size.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
11-06-10, 05:38 PM   #4
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,331
Originally Posted by Lulia View Post
I didn't use ClearAllPoints() (which explains why they didn't move properly when they did in my old example since I used the function in the old example).
To add to this, you can get away with using frame:SetPoint() without calling frame:ClearAllPoints() as long as you keep referencing the same point on the frame you're setting. If you have 2 or more points set at the same time, WoW will try to resize the frame to obey all the points set.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Odd Issue with Re-Positioning via Points


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off