It is currently November 28th, 2021, 5:33 am

Metatables & Rainmeter: Making editing from lua easy v5

Discuss the use of Lua in Script measures.
ailia
Posts: 34
Joined: August 6th, 2012, 9:56 pm
Location: Lurking

Metatables & Rainmeter: Making editing from lua easy v5

Post by ailia »

Metatables are an extremely powerful lua tool that allow definition of what happens when a table is accessed or written to. Using them things like meters, measures and variables can be accessed 'directly' without having to write bangs or indirectly access individual elements from SKIN.

Example 1
Configuring disabled hyopthetical meter [Foo] in lua

Code: Select all

SKIN:GetMeter('Foo'):Enable()
SKIN:GetMeter('Foo'):SetX(10)
SKIN:GetMeter('Foo'):SetY(10)
SKIN:Bang('!SetOption','Foo','MeasureName','Bar')
Using Metatables

Code: Select all

meters['Foo'].Disabled=0
meters['Foo'].X=10
meters['Foo'].Y=10
meters['Foo'].MeasureName='Bar'
Alternative Syntax

Code: Select all

meters.Foo.Disabled=0
meters.Foo.X=10
meters.Foo.Y=10
meters.Foo.MeasureName='Bar'
Example 2
Updating static text meter [Foo] that has UpdateDivider=-1

Code: Select all

SKIN:Bang('!SetOption', 'Foo', 'Text', 'Bar')
SKIN:Bang('!UpdateMeter', 'Foo')
Using Metatables

Code: Select all

meters.Foo.Text='Bar'
meters.Foo.UpdateMeter()
Example 3
Accessing Meter attributes, Measure and Variable values from Lua

Code: Select all

SKIN:GetMeasure('Foo1'):GetOption('MeasureName')
-- As a string
SKIN:GetMeasure('Foo2'):GetStringValue()
-- As a number
SKIN:GetMeasure('Foo2'):GetValue()
SKIN:GetVariable('Foo3')
Using Metatables

Code: Select all

measures.Foo1.MeasureName
-- As a string
measures.Foo2.GetStringValue()
-- As a number
measures.Foo2.GetValue()
variables.Foo3
Lua Rainmeter Metatables v5
Probably the last version unless errors are discovered.

Code: Select all

local ms = {__index = function(tb,key) if key == 'UpdateMeasure' then return function() SKIN:Bang('!UpdateMeasure',tb.__sectionname) end elseif tb.__section[key] then return function(...) return tb.__section[key](tb.__section,...) end else return (tb.__section.GetNumberOption and tb.__section:GetNumberOption(key,nil)) or tb.__section:GetOption(key) end end, __newindex = function(tb,key,value) SKIN:Bang('!SetOption',tb.__sectionname,key,value) end}
sections,variables = {__index = function(tb,key) sections[key]={} sections[key].__section, sections[key].__sectionname = SKIN:GetMeasure(key), key setmetatable(sections[key],ms) return sections[key] end},{__index = function(tb,key) return SKIN:GetVariable(key) end, __newindex = function(tb,key,value) SKIN:Bang('!SetVariable',key,value) end}
setmetatable(variables,variables)
setmetatable(sections,sections)
meters, measures = sections, sections
Lua Rainmeter Metatables v4
Fixed inheritance of Meter functions - Note changes to example 3 if using previous Versions

Code: Select all

local metameters, metameter, metameasures, metameasure, metavariables = {},{},{},{},{}
metameter.__newindex = function(tb,key,value) SKIN:Bang('!SetOption',tb.__metername,key,value) end
metameter.__index = function(tb,key)
	if tb.__meter[key] then return function(...) return tb.__meter[key](tb.__meter,...) end
	else return tb.__meter:GetOption(key) end
end
metameters.__index = function(tb,key)
	meters[key]={} meters[key].__meter, meters[key].__metername = SKIN:GetMeter(key), key
	setmetatable(meters[key],metameter)
	return meters[key]
end
metameasure.__newindex = function(tb,key,value) SKIN:Bang('!SetOption',tb.__measurename,key,value) end
metameasure.__index = function(tb,key)
	if key == 'UpdateMeasure' then return function() SKIN:Bang('!UpdateMeasure',tb.__measurename) end
	elseif tb.__measure[key] then return function(...) return tb.__measure[key](tb.__measure,...) end
	else return tb.__measure:GetNumberOption(key,nil) or tb.__measure:GetOption(key) end
end
metameasures.__index = function(tb,key)
	measures[key]={} measures[key].__measure, measures[key].__measurename = SKIN:GetMeasure(key), key
	setmetatable(measures[key],metameasure)
	return measures[key]
end
metavariables.__index = function(tb,key) return SKIN:GetVariable(key) end
metavariables.__newindex = function(tb,key,value) SKIN:Bang('!SetVariable',key,value) end
meters,measures,variables = {},{},{}
setmetatable(meters,metameters) setmetatable(measures,metameasures) setmetatable(variables,metavariables)
Lua Rainmeter Metatables v3
Removed nested local metatables, ram usage down a lot

Code: Select all

local metameters = {}
local metameter = {}
metameter.__newindex = function(tb,key,value)
	SKIN:Bang('!SetOption',tb.__metername,key,value)
end
metameter.__index = function(tb,key)
	return tb.__meter:GetOption(key)
end
metameters.__index = function(tb,key)
	meters[key]={}
	meters[key].__meter = SKIN:GetMeter(key)
	meters[key].__metername = key
	setmetatable(meters[key],metameter)
	return meters[key]
end
meters = {}
setmetatable(meters,metameters)

local metameasures = {}
local metameasure = {}
metameasure.__newindex = function(tb,key,value)
	SKIN:Bang('!SetOption',tb.__measurename,key,value)
end
metameasure.__index = function(tb,key)
	if key == 'String' then
		return tb.__measure:GetStringValue()
	elseif key == 'Value' then
		return tonumber(tb.__measure:GetValue())
	elseif key == 'MinValue' then
		return tonumber(tb.__measure:GetMinValue())
	elseif key == 'MaxValue' then
		return tonumber(tb.__measure:GetMaxValue())
	elseif key == 'UpdateMeasure' then
		return function() SKIN:Bang('!UpdateMeasure',tb.__measurename) end
	else
		local t = tb.__measure:GetNumberOption(key,nil)
		return t or tb.__measure:GetOption(key)
	end
end
metameasures.__index = function(tb,key)
	measures[key]={}
	measures[key].__measure = SKIN:GetMeasure(key)
	measures[key].__measurename = key
	setmetatable(measures[key],metameasure)
	return measures[key]
end
measures = {}
setmetatable(measures,metameasures)

local metavariables = {}
metavariables.__index = function(tb,key)
	return SKIN:GetVariable(key)
end
metavariables.__newindex = function(tb,key,value)
	SKIN:Bang('!SetVariable',key,value)
end
variables = {}
setmetatable(variables,metavariables)
Lua Rainmeter Metatables v2

Code: Select all

local metameters = {}
metameters.__index = function(tb,key)
	meters[key]={}
	local metameter = {}
	metameter.__newindex = function(tb2,key2,value2)
		SKIN:Bang('!SetOption',key,key2,value2)
	end
	metameter.__index = function(tb2,key2)
		return SKIN:GetMeter(key):GetOption(key2)
	end
	setmetatable(meters[key],metameter)
	return meters[key]
end
meters = {}
setmetatable(meters,metameters)

local metameasures = {}
metameasures.__index = function(tb,key)
	measures[key]={}
	local metameasure = {}
	metameasure.__newindex = function(tb2,key2,value2)
		SKIN:Bang('!SetOption',key,key2,value2)
	end
	metameasure.__index = function(tb2,key2)
		if key2 == 'String' then
			return SKIN:GetMeasure(key):GetStringValue()
		elseif key2 == 'Value' then
			return tonumber(SKIN:GetMeasure(key):GetValue())
		elseif key2 == 'MinValue' then
			return tonumber(SKIN:GetMeasure(key):GetMinValue())
		elseif key2 == 'MaxValue' then
			return tonumber(SKIN:GetMeasure(key):GetMaxValue())
		elseif key2 == 'UpdateMeasure' then
			return function() SKIN:Bang('!UpdateMeasure',key) end
		else
			local t = SKIN:GetMeasure(key):GetNumberOption(key2,nil)
			return t or SKIN:GetMeasure(key):GetOption(key2)
		end
	end
	setmetatable(measures[key],metameasure)
	return measures[key]
end
measures = {}
setmetatable(measures,metameasures)

local metavariables = {}
metavariables.__index = function(tb,key)
	return SKIN:GetVariable(key)
end
metavariables.__newindex = function(tb,key,value)
	SKIN:Bang('!SetVariable',key,value)
end
variables = {}
setmetatable(variables,metavariables)
Lua Rainmeter Metatables v1

Code: Select all

local metameters = {}
metameters.__index = function(tb,key)
	meters[key]={}
	local metameter = {}
	metameter.__newindex = function(tb2,key2,value2)
		SKIN:Bang('!SetOption',key,key2,value2)
	end
	metameter.__index = function(tb2,key2)
		return tonumber(SKIN:GetMeter(key):GetOption(key2))
	end
	setmetatable(meters[key],metameter)
	return meters[key]
end
meters = {}
setmetatable(meters,metameters)

local metameasures = {}
metameasures.__index = function(tb,key)
	measures[key]={}
	local metameasure = {}
	metameasure.__newindex = function(tb2,key2,value2)
		SKIN:Bang('!SetOption',key,key2,value2)
	end
	metameasure.__index = function(tb2,key2)
		if key2 == 'String' then
			return SKIN:GetMeasure(key):GetStringValue()
		elseif key2 == 'Value' then
			return tonumber(SKIN:GetMeasure(key):GetValue())
		elseif key2 == 'MinValue' then
			return tonumber(SKIN:GetMeasure(key):GetMinValue())
		elseif key2 == 'MaxValue' then
			return tonumber(SKIN:GetMeasure(key):GetMaxValue())
		elseif key2 == 'UpdateMeasure' then
			return function() SKIN:Bang('!UpdateMeasure',key) end
		else
			return tonumber(SKIN:GetMeasure(key):GetOption(key2))
		end
	end
	setmetatable(measures[key],metameasure)
	return measures[key]
end
measures = {}
setmetatable(measures,metameasures)

local metavariables = {}
metavariables.__index = function(tb,key)
	return SKIN:GetVariable(key)
end
metavariables.__newindex = function(tb,key,value)
	SKIN:Bang('!SetVariable',key,value)
end
variables = {}
setmetatable(variables,metavariables)
Last edited by ailia on August 8th, 2012, 7:48 pm, edited 3 times in total.
User avatar
MerlinTheRed
Rainmeter Sage
Posts: 889
Joined: September 6th, 2011, 6:34 am

Re: Metatables & Rainmeter: Making changing stuff from lua e

Post by MerlinTheRed »

This is a really interesting and flexible way of doing some kind of object orientation in Lua. I wonder if it gets confusing if you don't do it right. Thanks for pointing out this Lua feature. And thanks for sharing your code. I assume one should put this in the Initialize() function of a script?
Have more fun creating skins with Sublime Text 2 and the Rainmeter Package!
ailia
Posts: 34
Joined: August 6th, 2012, 9:56 pm
Location: Lurking

Re: Metatables & Rainmeter: Making changing stuff from lua e

Post by ailia »

Yep, not much else to it.