Thread Tools Display Modes
06-08-05, 04:19 PM   #1
diiverr
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jan 2005
Posts: 67
What am I missing?

OK. I am trying to make a configurable texture in game.

When I paint this frame:
Code:
<Frame name="DiivSkins_Hbar1" frameStrata="BACKGROUND" inherits="DiivSkins_hbarTemplate" parent="UIParent">
	<Size>
		<AbsDimension x="512" y="46"/>
	</Size>
	<Layers>
		<Layer level="ARTWORK">
			<Texture name="DiivSkins_hbar1Texture" file="Interface\AddOns\DiivSkins\Skins\diivskins_01">
				<TexCoords left="0.0019531" right="1.0" top="0.0" bottom="0.0898437"/>
			</Texture>
		</Layer>
	</Layers>
	<Anchors>
		<Anchor point="BOTTOM">
			<Offset>
				<AbsDimension x="215" y="550"/>
			</Offset>
		</Anchor>
	</Anchors>
</Frame>
I get this image: CLICKY


Now, I set up the following lua functions to alter that texture via a slider, and (hopefully) save it across sessions (most of this is hacked up and taken from the SquidMod code):
Code:
function DS_OnLoad()
	DiivSkins_LoadVariables();
	this:RegisterEvent("VARIABLES_LOADED");
end

function DiivSkins_LoadVariables()
	if not DiivSkinSettings then
		DiivSkinSettings = { };
	end
end

function DS_OnEvent()
	if event=="VARIABLES_LOADED" then
		if not DS_UsedBefore then
			-- do one-time stuff for first use here

			-- display the primary game menu without a keypress
			GameMenuFrame:Show();
			-- display an attatched text frame to this menu
			DS_Init:Show();

			-- Swap in the placeholder DiivSkins button on the game menu
			DS_GameMenuButton:Hide();
			DS_GameMenuButton_Init:Show();

			--register the variable as true, so the above never happens again.
			DS_UsedBefore = true
			
			--update my slider variables
		else if not (DiivSkinSettings) then
			DiivSkinSettings.hbar1 = {}
		end
	end
end

function DiivSkins_hbar1Update()
	if(DiivSkinsSettings) then
		elseif(DiivSkinSettings.hbar1 == 2) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.8984375, 0.9882812);
		elseif(DiivSkinSettings.hbar1 == 3) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.8085937, 0.8984375);
		elseif(DiivSkinSettings.hbar1 == 4) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.71875, 0.8085937);
		elseif(DiivSkinSettings.hbar1 == 5) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.6289062, 0.71875);
		elseif(DiivSkinSettings.hbar1 == 6) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.5390625, 0.6289062);
		elseif(DiivSkinSettings.hbar1 == 7) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.4492187, 0.5390625);
		elseif(DiivSkinSettings.hbar1 == 8) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.359375, 0.4492187);
		elseif(DiivSkinSettings.hbar1 == 9) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.2695312, 0.359375);
		elseif(DiivSkinSettings.hbar1 == 10) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.1796875, 0.2695312);
		elseif(DiivSkinSettings.hbar1 == 11) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.0898437, 0.1796875);
		elseif(DiivSkinSettings.hbar1 == 12) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.0, 0.0898437);
		end
	end
end
The OnLoad and OnEvent functions are called elsewhere in my XML, the "Update" function iis called from the slider XML:
Code:
<Slider name="DiivSkins_hbar1Slider" inherits="OptionsSliderTemplate">
	<Size>
		<AbsDimension x="160" y="17"/>
	</Size>
	<Anchors>
		<Anchor point="CENTER"/>
	</Anchors>
	<Scripts>
		<OnLoad>
			getglobal(this:GetName().."Text"):SetText("Horizontal Bar 1");
			getglobal(this:GetName().."High"):SetText("12 slots");
			getglobal(this:GetName().."Low"):SetText("2 slot");
			this:SetMinMaxValues(2, 12);
			this:SetValueStep(1);
		</OnLoad>
		<OnShow>
			if (DiivSkinSettings.hbar1) then
				this:SetValue(DiivSkinSettings.hbar1);
			end
		</OnShow>
		<OnValueChanged>
			DiivSkinSettings.hbar1 = this:GetValue();
			DiivSkins_hbar1Update();
		</OnValueChanged>
	</Scripts>
</Slider>


Now, here's where it gets odd. Here's another image: CLICKY (for reference)

The variable, DiivSkinSettings.hbar, is saved in my savedvariables, and it does save the textCoord's of whatever the slider was last on, but It only refreshes them after I open up that page of my configuration doohickey. Until that point, the full 12 slot bar is displayed. After the config page is opened and then closed, the correct "slot" confguration will persist.

The above code produces no errors, but has the mentioned issues. I tried just about everything I could think of to check for the value of the slider, but nothing worked. Almost every variant produced errors mostly pointing at the "DiivSkins_hbar1Update()" function. Either the reference in the slider XML was "referencing a nil value", or the lua broke alltogether, disabling all the other functions for buttons toggles and such that are present in the lua. This include trying to call the Update function from anywhere other than the <OnShow> in the slider XML. From there, its fine. Anywhere else, I get "an attempt to call a nil value" or it flat out tells me the function is broken.

I hope I explained that well enough. I'm sure I'm making some pretty elementary mistakes, but I feel like I'm getting close anyway.

Any help?
  Reply With Quote
06-08-05, 04:57 PM   #2
Gello
A Molten Giant
AddOn Author - Click to view addons
Join Date: Jan 2005
Posts: 521
At a casual glance, a couple things throw up flags for me:

else if not (DiivSkinSettings) then
DiivSkinSettings.hbar1 = {}
end

If the above happens, then it will give an error. The above says if this table doesn't exist, then create a subtable under this non-existent table.

What you probably want is:

else if not (DiivSkinSettings) then
DiivSkinSettings = {}
DiivSkinSettings.hbar1 = (some default value)
end

On the value not chaning right away: A slider's OnValueChanged will get called BEFORE your variables are loaded. As part of a slider's initialization it will call OnValueChanged. This may be why its last state is not being saved initialially. I don't see a DiivSkins_hbar1Update() but I suspect it's assuming variables are loaded and they're not yet. (and in fact it'd be overwritten by this:GetValue())

How I handle sliders is this:
1. In the mod's initialization, after VARIABLES_LOADED, I slider:SetValue(last position)
2. In the slider's OnValueChanged() function, I check first if the mod is loaded, and if it is, then I assume the current position is valid and work with it from there.

When troubleshooting a sequence of events I'll often pepper my code with a lot of DEFAULT_CHAT_FRAME:AddMessage("In OnValueChange now") and stuff like the above will stand out right away.
  Reply With Quote
06-08-05, 05:46 PM   #3
diiverr
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jan 2005
Posts: 67
Thank you much for the reply Gello, that was very helpful. I knew I had issues with my vairables, I just didn't know how or why. I was quite frankly astonished it worked as well as it did at first go.

I will have to try the chat frame mssg's. I thought maybe the "stock" XML frame was being rendered until the <OnShow> update worked its way into the mix, but I wasn't sure if it was that, or a variable value of 12 for some reason. That will be a good way to know for sure.


I was also worried about the way the update function read.

If yadayada then
elseif yadayada then
something yada

Seems logical that it should read more to the tune of

If yadayada then
something yada
elseif yadayada then
something yada

I thought for sure that was where "flags might have been thrown up," but I couldn't seem to get anything to work right there. Typically, my brain's idea of logic and lua's idea of logic seem to be at odds most of the time anyway.
  Reply With Quote
06-08-05, 08:19 PM   #4
Sathanas
A Deviate Faerie Dragon
 
Sathanas's Avatar
AddOn Author - Click to view addons
Join Date: May 2005
Posts: 15
Originally Posted by Gello
When troubleshooting a sequence of events I'll often pepper my code with a lot of DEFAULT_CHAT_FRAME:AddMessage("In OnValueChange now") and stuff like the above will stand out right away.
Hehe i thought i was the only one to do that.

My chat box looks funny when im working on something new.

thingy: 1
thatstuff: 5
things: Hunter
__________________
--Sathanas
  Reply With Quote
06-09-05, 06:51 AM   #5
diiverr
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jan 2005
Posts: 67
[grumble]
While your post makes sense to me, I'm afraid I can't get the syntax correct. Heck, I can't even get the actual value to display in a CHAT_FRAME dump. I can display a message, but nothing productive.

Originally Posted by Gello
On the value not chaning right away: A slider's OnValueChanged will get called BEFORE your variables are loaded. As part of a slider's initialization it will call OnValueChanged. This may be why its last state is not being saved initialially. I don't see a DiivSkins_hbar1Update() but I suspect it's assuming variables are loaded and they're not yet. (and in fact it'd be overwritten by this:GetValue())

How I handle sliders is this:
1. In the mod's initialization, after VARIABLES_LOADED, I slider:SetValue(last position)
2. In the slider's OnValueChanged() function, I check first if the mod is loaded, and if it is, then I assume the current position is valid and work with it from there.

When troubleshooting a sequence of events I'll often pepper my code with a lot of DEFAULT_CHAT_FRAME:AddMessage("In OnValueChange now") and stuff like the above will stand out right away.
What I think is happening is that my savedvariable texture reference, while being saved, is not being called until the slider is visible. I verified this by changing the root textCoord's of the original xml frame, as this frame is not hidden. (I just did something wacky to get a distorted image displayed).

On start up, I get the base (distorted) XML texture. Once I open the slider page, then the frame's SetTexture reference from the slider value is recognized and employed, and all is well. This will persist until reload/relog. Then we start over. The variable is saved, but not displayed, until I access the slider. I don't even need to adjust it, just make it visible on screen by opening its page in my config UI. The moment the slider is displayed on screen, the texture for the frame in question is displayed, correctly, from the saved variable as well.


Could you maybe point me at an AddOn that initializes referencing a Slider Value? I couldn't seem to find one, but maybe looking at how its done might help me. My brain tells me the slider value isn't the problem, but that I'm just not actively displaying the data contained in the SavedVariable on initialization.

I would think just running the update function would accomplish this, but I can't for the life of me get that DiivSkins_hbar1Update() function (posted earlier) to fire from anywhere other than the <OnValueChanged> call of the slider xml.

It always returns a ...attempt to call global ... (a nil value) pertaining to itself if I try to call it from an OnEvent or an OnLoad.
[/grumble]



Thanks in advance for any assistance anyone might be able to give, and for patronizing the unedumaceted.
  Reply With Quote
06-09-05, 07:50 AM   #6
Beladona
A Molten Giant
 
Beladona's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2005
Posts: 539
You need to do the following:

Setup your slider to change the savedVariable, and then call your textureUpdate function. You already have that so you are almost there...

Setup your textureUpdate function to check for the existence of the variable it needs. if the variable isn't there, then it needs to be created, which I assume you have elsewhere in your script, so we don't need to go over that. Once it has the varaible it needs, then change the texture. You have that, although the syntax is badly written, so you may want to fix that. I can assist if you need.

The final thing that needs to be done, which is your primary problem, is that you need to add a script section to your DiivSkins_Hbar1 frame. You see, the slider will NOT do anything until it gets shown. That means the config options have to be opened EVERY session in order for your texture to get updated. So you need to add the texture update to something that will be on screen every session. Since the frame mentioned above is the one with the texture you plan to change, it should have the update script in its OnEvent section. Do it like this:

<OnLoad>this:RegisterEvent("VARIABLES_LOADED");</OnLoad>
<OnEvent>if (event == "VARIABLES_LOADED") then TextureUpdateFunction(); end</OnEvent>

Basically that means that whenever someone loads the game, and after the varaibles get loaded, the texture update function will get run, which checks to see what they have set for that variable (if at all, else it creates a default value) and then udpates the texture accordingly.

Hopefully this gets you where you are trying to go. As always, let me know if you need any assistance. Especially with that texture Update function, as it looks like you didn't format the if, else, and elseif's correctly...

Last edited by Beladona : 06-09-05 at 08:01 AM.
  Reply With Quote
06-09-05, 07:58 AM   #7
Gello
A Molten Giant
AddOn Author - Click to view addons
Join Date: Jan 2005
Posts: 521
It's not the best mod for an example of sliders, but Recap here has several sliders in RecapOptions.lua and RecapOptions.xml.

In the xml, I define the min/max/default of the slider in the slider's tag.

<Slider name="RecapIdleFightSlider" orientation="HORIZONTAL" enableMouse="true" minValue="5" maxValue="60" defaultValue="10" valueStep="1">

The scripts section only has tooltip bits and OnValueChanged:

<Scripts>
<OnEnter>
Recap_OnTooltip("IdleFightSlider");
</OnEnter>
<OnLeave>
GameTooltip:Hide();
</OnLeave>
<OnValueChanged>
Recap_IdleFightSlider_OnValueChanged(arg1);
</OnValueChanged>
</Scripts>


In/after the VARIABLES_LOADED event, I make recap_temp.Loaded=true and call Recap_InitializeOptions():

function Recap_InitializeOptions()
local chatname,chatid,i;
RecapAutoFadeSlider:SetValue(recap.Opt.AutoFadeTimer.value);
RecapIdleFightSlider:SetValue(recap.Opt.IdleFightTimer.value);
RecapMaxRowsSlider:SetValue(recap.Opt.MaxRows.value);
RecapMaxRankSlider:SetValue(recap.Opt.MaxRank.value);
etc
end

To set all the values from the last session.

Then OnValueChanged is very simple:

function Recap_IdleFightSlider_OnValueChanged(arg1)
if recap_temp.Loaded and arg1 then
RecapIdleFightSlider_Text:SetText(arg1.." seconds");
recap.Opt.IdleFightTimer.value = arg1;
end
end

Try moving stuff out of the OnLoad/OnShow and into your VARIABLES_LOADED event. That way you're not dependent on when the UI gets around to loading up your UI during startup.

I would think just running the update function would accomplish this, but I can't for the life of me get that DiivSkins_hbar1Update() function (posted earlier) to fire from anywhere other than the <OnValueChanged> call of the slider xml.
Don't try fitting everything into the xml. In many cases it's better to manipulate stuff in your OnEvent handlers than the control's own event handlers.

Last edited by Gello : 06-09-05 at 08:01 AM.
  Reply With Quote
06-09-05, 08:03 AM   #8
Beladona
A Molten Giant
 
Beladona's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2005
Posts: 539
his problem isn't the slider. The slider is doing what it needs to do. His problem is that when he changes the slider, it changes the texture, as intended (or it should) but if you log out, and back in, the texture will be at the default until he opens and updates the slider.

He simply needs an onload in his initial frame to get the variable when the player logs in. The slider only needs to change it if they plan on changing it, not change it on game-load.

On a side note, I could easily fix your issues as posted and post the updated code, but I prefer not to. The only way for a person to learn (or at least the way I learn best) is by breaking it, and fixing it yourself. So I will kinda nudge you in the right direction, and help you when you need it, but anything more than that might hurt your own learning process

Last edited by Beladona : 06-09-05 at 08:14 AM.
  Reply With Quote
06-09-05, 08:37 AM   #9
diiverr
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jan 2005
Posts: 67
Thank you for the replies. I know I'm clueless, but I sincerly appreciate your patience. I really am learning a lot.

Beladona,
I did as suggested... The update function now reads:
Code:
function DiivSkins_hbar1Update()

	if(DiivSkinsSettings) then
		if not (DiivSkinSettings) then
			DiivSkinSettings = {}
			DiivSkinSettings.hbar1 = 2
		end
		elseif(DiivSkinSettings.hbar1 == 1) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.9023437, 0.984375);

		elseif(DiivSkinSettings.hbar1 == 2) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.8203125, 0.9023437);

		elseif(DiivSkinSettings.hbar1 == 3) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.7382812, 0.8203125);

		elseif(DiivSkinSettings.hbar1 == 4) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.65625, 0.7382812);

		elseif(DiivSkinSettings.hbar1 == 5) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.5742187, 0.65625);

		elseif(DiivSkinSettings.hbar1 == 6) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.4921875, 0.5742187);

		elseif(DiivSkinSettings.hbar1 == 7) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.4101562, 0.4921875);

		elseif(DiivSkinSettings.hbar1 == 8) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.328125, 0.4101562);

		elseif(DiivSkinSettings.hbar1 == 9) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.2460937, 0.328125);

		elseif(DiivSkinSettings.hbar1 == 10) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.1640625, 0.2460937);

		elseif(DiivSkinSettings.hbar1 == 11) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.0820312, 0.1640625);

		elseif(DiivSkinSettings.hbar1 == 12) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.0, 0.0820312);
		end
	end
end
I then added the suggested <Scripts> to the original texture frame's xml. (better quote them too, just to be safe)

Code:
		<Scripts>
			<OnLoad>
				this:RegisterEvent("VARIABLES_LOADED");
			</OnLoad>
			<OnEvent>
				if (event == "VARIABLES_LOADED") then 
					DiivSkins_hbar1Update(); 
				end
			</OnEvent>
		</Scripts>
That, save the check in the Update function itself for the variable, is a variation of what I have been trying, although I was calling for the Update function from elsewhere, typically in my normal OnEvent function. The net result of your suggestion, assuming I executed it properly) produced the same nil error as before regarding the Update function itself. I get this error at startup or reload, or, I assume, when VARIABLES_LOADED fires.

you did say:
... although the syntax is badly written, so you may want to fix that. I can assist if you need.
I think(?) Gello set me straight there. I hope I did that correctly. For the record, I will ALWAYS welcome help in that arena, or any other for that matter, so don't be shy, and thank you.




Gello,

I will definitely take a look at Recap, and see if that doesn't shed any light for me, thank you. From a cursory examination of what you posted here, there does seem to be some pretty fundamental structural differences in the way you coded it all. (I don't understand the "arg" notion either, but admittedly I haven't attempted to dissect them yet.)
EDIT: Whoah, how have I missed this! (sorry, just got into game with recap, that looks to be a very slick little toy. )

RE:
Don't try fitting everything into the xml. In many cases it's better to manipulate stuff in your OnEvent handlers than the control's own event handlers.
I probably poorly worded that. When I said fire, I meant I have the line: DiivSkins_hbar1Update(); in my <OnValueChanged>, and that seems to be the only place it doesn't return a nil error when called.

Last edited by diiverr : 06-09-05 at 08:56 AM.
  Reply With Quote
06-09-05, 08:42 AM   #10
diiverr
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jan 2005
Posts: 67
Something looked odd in the function I posted, so I tried this as well:
Code:
function DiivSkins_hbar1Update()

		if not (DiivSkinSettings) then
			DiivSkinSettings = {}
			DiivSkinSettings.hbar1 = 2
			
		elseif(DiivSkinSettings.hbar1 == 1) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.9023437, 0.984375);

		elseif(DiivSkinSettings.hbar1 == 2) then
			DiivSkins_hbar1Texture:SetTexCoord(0.0, 1.0, 0.8203125, 0.9023437);

etc.
still produces a nil error.

edit: sorry, still produces a nil error when called after the VARIABLES_LOADED event fires. (rather than from the slider <OnValueChanged>, where it works)

Last edited by diiverr : 06-09-05 at 08:49 AM.
  Reply With Quote
06-09-05, 09:08 AM   #11
Gello
A Molten Giant
AddOn Author - Click to view addons
Join Date: Jan 2005
Posts: 521
The important bit, which should be stressed above all else, is that OnValueChanged will happen BEFORE variables are loaded. It's part of a slider's initialization when the game loads up.

Do you have DiivSkinSettings defined outside the functions above? Looking at it more closely I wonder that you don't get nil errors in the initial OnValueChanged.

If your mod looks like:
Code:
function OnLoad()
	this:RegisterEvent("VARIABLES_LOADED")
end

function OnEvent()
	if event=="VARIABLES_LOADED" then
		DiivSkinSettings = {}
		DiivSkins_hbar1Update();
	end
end

Then in the xml:
<OnValueChanged>
	DiivSkinSettings.hbar1 = this:GetValue();
	DiivSkins_hbar1Update();
</OnValueChanged>
is going to be a mess. Because DiivSkinSettings is not defined yet. (OnValueChanged will get called BEFORE variables are loaded)

You can do this:
Code:
DiivSkinSettings = {}

function OnLoad()
	this:RegisterEvent("VARIABLES_LOADED")
end

function OnEvent()
	if event=="VARIABLES_LOADED" then
		DiivSkins_hbar1Update();
	end
end
By moving DiivSkinSettings = {} outside the functions, when the xml is loaded and it hits the Script file="whatever.lua", it will run the lua file and make DiivSkinSettings = {} before anything happens in your xml.

Or you can do
Code:
<OnValueChanged>
if DiivSkinSettings then
	DiivSkinSettings.hbar1 = this:GetValue();
	DiivSkins_hbar1Update();
end
Other stuff I notice:

Code:
<OnShow>
	if (DiivSkinSettings.hbar1) then
		this:SetValue(DiivSkinSettings.hbar1);
	end
</OnShow>
If DiivSkinSettings isn't defined yet (ie, if before VARIABLES_LOADED), then this will give an error. It's trying to see if a value beneath an undefined table exists.

When checking if something exists, if it's a table then the elements above it must exist or it will give an error. the above should read:
Code:
<OnShow>
	if DiivSkinSettings and DiivSkinSettings.hbar1 then
		this:SetValue(DiivSkinSettings.hbar1);
	end
</OnShow>
If DiivSkinSettings doesn't exist it will fail right away. If it exists it will see if hbar1 beneath it exists.

But again, realize that OnValueChanged() gets called BEFORE VARIABLES_LOADED. You may think OnValueChanged() is the result of someone moving the slider but it can (and is) also the UI setting the default value.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » What am I missing?

Thread Tools
Display Modes

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