It is currently March 28th, 2024, 5:17 pm

How to approach a problem...

Discuss the use of Lua in Script measures.
Post Reply
FlyingHyrax
Posts: 232
Joined: July 1st, 2011, 1:32 am
Location: US

How to approach a problem...

Post by FlyingHyrax »

Context is here.

For this skin/script, I want to be able to have the number of bars used be a setting... that is, right now, it has settings for the width of the histogram and the width of an individual bar (plus a spacer). So the user can change how wide the histogram is, then change how wide an individual bar is, and the script takes that and divides the width of the skin by the width of bar to figure out how many bars will be in the histogram. Then the script writes the correct number of image meters to the skin file.

I'm starting to think that this isn't the best approach, mainly because if you start the skin with, say, 100 bars in the histogram, then reduce that to 50, then 50 left over image meters stay in the skin file unless you go and remove them yourself manually. Not so great.

So I'm wondering - is there a way to have the script check the number of image meters in the file against the number that it is supposed to have, and delete excess meters? I think I can at least figure out how to search the skin file for image meters since the meter names are just numbers... but I have no idea how to "delete" meters from the file, and even if that's possible it feels like it would end up being more trouble than it's worth.

Another approach might be to have all the image meters already in the skin file, and just hide/unhide them as necessary. I think I could figure that out, but then you have a maximum number of bars that can be used for the histogram.

After writing this out, I'm leaning toward the second option... just having 1000 image meters sitting there shouldn't hurt anything, right?

In any case, I'm sure there is probably a different, better approach to this whole skin concept that I haven't even thought of, hence the forum post.

Postscript - Any general pointers on style/convention are appreciated. I haven't seen Rainmeter/Lua snippets that, for instance, show global variables being declared outside the Initialize function... I'm initializing them inside Initialize() but declaring them at the top of the file because I figured that if they were declared in initialize they would only be in the scope of that function, but is that at all correct?

Current script code...

Code: Select all

Meters = {}
Values = {}
numBars = _
height = _
measure = _
gap = _

direction = 0	--0 for right to left, 1 for left to right
orient = 0		--0 for face up, 1 for face down

function Initialize()
	w = SELF:GetNumberOption('Width')
	gap = SELF:GetNumberOption('Gap')
	barW = SELF:GetNumberOption('BarWidth')
	numBars = math.floor(w / (gap+barW))
	
	direction = SELF:GetNumberOption('FlipX')
	orient = SELF:GetNumberOption('FlipY')
	height = SELF:GetNumberOption('Height') - gap
	measure = SKIN:GetMeasure(SELF:GetOption('Msr'))
	
	print(numBars .. ' | ' ..height)
	
	SKIN:Bang('!WriteKeyValue',1,'Meter','IMAGE')
	SKIN:Bang('!WriteKeyValue',1,'MeterStyle','sBar')
	SKIN:Bang('!WriteKeyValue',1,'X','#Gap#r')
	Meters[1] = SKIN:GetMeter(1)
	Values[1] = 0
	
	for i=2,numBars do
		SKIN:Bang('!WriteKeyValue',i,'Meter','IMAGE')
		SKIN:Bang('!WriteKeyValue',i,'MeterStyle','sBar')
		Meters[i] = SKIN:GetMeter(i)
		Values[i] = 0
	end
end

function Update()
	moveValues(measure:GetRelativeValue(),direction)
	updateHeight(orient)
	return
end


function updateHeight(dir)	
	for i=1,numBars do
		h = math.floor((Values[i])*height)
		if dir == 1 then
			y = gap
		else
			y = height - h - gap
		end
		SKIN:Bang('!SetOption ' .. Meters[i]:GetName() .. ' H ' .. h)
	--		Meters[i]:SetH(h)
			Meters[i]:SetY(y)
	end
end

function moveValues(newest,dir)
	if dir == 1 then
		for i=numBars,1,-1 do
			Values[i] = Values[i-1]
		end
		Values[1] = newest
	else
		for i=1,numBars do
			Values[i] = Values[i+1]
		end
		Values[numBars] = newest
	end
end
User avatar
smurfier
Moderator
Posts: 1931
Joined: January 29th, 2010, 1:43 am
Location: Willmar, MN

Re: How to approach a problem...

Post by smurfier »

I would leave the image meters in the skin for the user to clean up. Removing them from the Lua side could prove to be difficult.

Variables are only local if they are declared as such. If they are not declared as local, then they are global, no matter where you create them.

If I interpret your code correctly I have made some minor adjustments.

Code: Select all

function Initialize()
	Meters = {}
	Values = {}
	gap = SELF:GetNumberOption('Gap', 0)
	numBars = math.floor(SELF:GetNumberOption('Width', 1) / (gap + SELF:GetNumberOption('BarWidth', 1)))
	
	direction = SELF:GetNumberOption('FlipX', 0) == 1 -- 0 for right to left, 1 for left to right
	orient = SELF:GetNumberOption('FlipY', 0) -- 0 for face up, 1 for face down
	height = SELF:GetNumberOption('Height', 0) - gap
	measure = SKIN:GetMeasure(SELF:GetOption('Msr'))
	
	print(numBars .. ' | ' .. height)

	SKIN:Bang('!WriteKeyValue', 1, 'X', '#Gap#r')
	for i = 1, numBars do
		SKIN:Bang('!WriteKeyValue', i, 'Meter', 'IMAGE')
		SKIN:Bang('!WriteKeyValue', i, 'MeterStyle', 'sBar')
		Meters[i] = SKIN:GetMeter(i)
		Values[i] = 0
	end
end

function Update()
   if dir then
      table.remove(Values) -- Remove last value
      table.insert(Values, newest, 1) -- Add value as index one
   else
      table.remove(Values, 1) -- Remove first value
      table.insert(Values, newest) -- Add value as last index
   end

	for i = 1, numBars do
		local h = math.floor(Values[i] * height) -- Local so that it doesn't exist outside of this for statement
		SKIN:Bang('!SetOption', Meters[i]:GetName(), 'H', h)
		--Meters[i]:SetH(h)
		Meters[i]:SetY(dir and gap or (height - h - gap))
	end
end
FlyingHyrax
Posts: 232
Joined: July 1st, 2011, 1:32 am
Location: US

Re: How to approach a problem...

Post by FlyingHyrax »

Thank you smurf, I appreciate the help!

I haven't tested your version yet, but looking over it I think it will work just the same, and it is definitely much cleaner. (I also like your definition of "minor adjustments...")

I missed being able to specify a default value for the SELF:GetOption() function, that's nice. And this is totally fantastic:

Code: Select all

  if dir then
      table.remove(Values) -- Remove last value
      table.insert(Values, newest, 1) -- Add value as index one
   else
      table.remove(Values, 1) -- Remove first value
      table.insert(Values, newest) -- Add value as last index
   end
...I remember seeing table functions in the Lua documentation but didn't think to use them like that. Very neat.

This line threw me for a loop, but I found it in the Lua manual. Not intuitive, but concise... I assumed that Lua handled logical operators like && and || from Java, but I guess not quite?

Code: Select all

Meters[i]:SetY(dir and gap or (height - h - gap))
User avatar
smurfier
Moderator
Posts: 1931
Joined: January 29th, 2010, 1:43 am
Location: Willmar, MN

Re: How to approach a problem...

Post by smurfier »

Read this article, the relevant section being "Ternary operators".
FlyingHyrax
Posts: 232
Joined: July 1st, 2011, 1:32 am
Location: US

Re: How to approach a problem...

Post by FlyingHyrax »

Thanks!
Post Reply