It is currently April 24th, 2024, 11:40 pm

Using LUA to create meters and measures (not whole skins)?

Discuss the use of Lua in Script measures.
oliver+
Posts: 4
Joined: May 8th, 2014, 10:36 pm

Using LUA to create meters and measures (not whole skins)?

Post by oliver+ »

Hi,
is it possible to create new meters and measures via LUA?
A typical situation i could use this is in stock market skin. Thoose skins are allways conceived that for every share that is displayed a new meter and a new measure is in the skin file. In most cases those skins got delivered with two versions: one version showing 5 and one version showing 8 shares (or similar), so when you need a different number you have to edit one of these file by yourself (adding or removing meters/measures manually).

But mostly the meters and measures for each share differ only in some very few things, mostly just the position and the name (which could be accessed via an array).
Anyway with a simple for loop one where able to create the source code of any number of share meters/measures easily.
And that is what i want to do. I want to create a skin using a for loop so that the user only have to edit a list (maybe in the LUA scriptfile or in an additional file that get read by the lua script), and the lua script will create an according number of corresponding meters/measures.
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Using LUA to create meters and measures (not whole skins

Post by jsmorley »

Yes, it certainly is possible, but not trivial if you don't already have some knowledge of Lua, or have other programming experience. Rainmeter code is not really "programming", but Lua, even though it is quite simple compared to other languages, really is...

Also there is at least one "gotcha" I will go into later.

What I would do is have the core of the skin as a normal .ini file with the [Rainmeter], [Variables] and any other sections (measures or meters) that are not related to getting the stock items and displaying them.

Have an @Include file, say stocks.inc, that will be the file that will have the measures and meters to get the stocks and display them.

In the main .ini file put this @Include option where it makes sense to start the measures and meters. Don't forget that a skin .ini file is read and "built" in the order things are in the .ini file, and while it generally doesn't matter about the order of measures (although it can in some specific instances), it can matter a lot with meters, if you are using relative positioning (which you certainly will want to do) or have meters you want to be "in front" or "in back" of other meters. In any case, remember that the information in the @Include file will be "inserted" right where you put it in the .ini file.

Note: Nothing says you couldn't have the Lua script create the entire skin and not bother with an @Include file.

Have your Lua script measure somewhere early on in the skin, but do NOT have it execute automatically. That can only lead to an endless loop. Have it so the user has to click on some button like "rebuild skin" to execute the script that runs the .lua file. I don't know how you intend to use this, but what you can't do is have the skin be loaded, run the Lua to create the measures and meters, and refresh the skin to "see" the new stuff. That is a certain endless loop. You need to think through how you will use this. You are going to have to refresh the skin after you change code in it with Lua.

Anyway, in the Lua just use the io library - http://lua-users.org/wiki/IoLibraryTutorial to open and read in whatever information you want from some external "MyStocks.txt" file, and either put the information in a table (an array essentially) or just use it as you read it in.

Have the Lua use the io library to open that file "stocks.inc" (our include file) with the "w+" open parameter. That will create a new file each time. Then use a loop to write out the lines of code you need for your measures and meters. When you are done, close the file, and send a bang from Lua to refresh the skin.

This way you just have to edit MyStocks.txt with more / less / changed information, then save that and click on that "rebuild skin" button in the skin I suggested earlier.

Now the "gotcha". You will need to be careful that everything you write to the skin is plain ASCII / ANSI text. You won't be able to write Unicode characters to the .inc file, as Lua can only do UTF-8, and Rainmeter won't accept UTF-8 as an @Include file, but only ANSI or UTF-16. This is probably going to be a show-stopper if you are using international characters, any language but English, or any special symbols. If you are planning to use a German character set, this is probably not going to work with Lua. You might be better off to just have Rainmeter execute some external program you write in VBS, AutoIt, C++, whatever.

So to end this, if you are not either already pretty good with Lua, or want to really take this on and learn how to use Lua (again, this won't be a trivial little script, although certainly doable) then I don't recommend this. Nobody here is going to do it for you, although we would certainly be glad to help you if you get stuck on something.
oliver+
Posts: 4
Joined: May 8th, 2014, 10:36 pm

Re: Using LUA to create meters and measures (not whole skins

Post by oliver+ »

Thanks for your answer, and do not worry i will not ask someone to do it for me.
I do not know much aboput LUA in particular but i have some experience in programming.
In fact i allready wrote a little lua script / ini combo that shows a graphic and rotates it (a simple rotation animation).
But i hoped that it would be possible to simply create a new measure (as objects in the memory) in a way or similar you can edit measures/meters simply by changing its attributes (via lua), without having to really write or change the actual ini file.

Btw: if someone is interested in my rotation animation script, if only to comment. Here it is :) :

I wrote a function that rotates any meter (identified by its name) by a given angle, with the given (x,y) center of rotation. I call this function in the Update() function to create a simple roation animation.
The meter can be like this:

Code: Select all

[MeterSimon]
 Meter=Image
 ImageName=#@#char_simon.gif
 X=0
 Y=60
The LUA script looks like this:

Code: Select all

function RotateMeter(meter,angle,x,y)
	local tx, ty, a,b,c,d

	a =  math.cos  (math.rad(angle))
	b = -math.sin  (math.rad(angle))
	c = -b
	d =  a

	tx = x - x*a - y*c
	ty = y - x*b - y*d

	SKIN:Bang('!SetOption', meter, 'TransformationMatrix', a .. ';' .. b .. ';' .. c .. ';' .. d .. ';' .. tx .. ';' .. ty)
end

function Initialize()
	angle = 360
end

function Update()
	angle = angle + 7 -- this sets the rotation speed

	if angle >= 360 then -- this preventing a variable overflow
		angle = angle - 360
	end

	RotateMeter('MeterSimon',angle,10,89)

	return angle
end
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Using LUA to create meters and measures (not whole skins

Post by jsmorley »

You can't create measures or meters "in memory" at all in Rainmeter. If it isn't read in from the .ini (or an @Include file) when the skin is loaded or refreshed then it doesn't exist.

You can use !SetOption to add or change just about any option on any existing measure or meter however. About the only thing you can't dynamically add or change is the [SectionName] and the "type" (i.e. Meter=String or Measure=Plugin). You can also use !SetOption to dynamically "enable / disable" measures or "hide / show" meters.

But if you need 10 measures and 10 meters to get and display information, there will need to be at least 10 measures and 10 meters in the skin when it is loaded or refreshed. They can be pretty minimal and set to "disabled / hidden" at the start, and have the Lua set all the options on them. Then you could probably get around doing a "refresh" and any endless loops.
oliver+
Posts: 4
Joined: May 8th, 2014, 10:36 pm

Re: Using LUA to create meters and measures (not whole skins

Post by oliver+ »

Thanks i understand. The only problem with the method you proposed is that the user had to click a button or simply has to do something to start the skin. The problem is that it is not possbile to automate the starting of the skin.
But thanks anyway i will think about this for a while and then decide.
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Using LUA to create meters and measures (not whole skins

Post by jsmorley »

Ok, if you can live with having the maximum number of measures and meters in the skin to start with, they can be pretty minimal as I said. This would work with no errors:

Code: Select all

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1

[MeasureSite]
Measure=Plugin
Plugin=WebParser

[MeasureChild1]
Measure=Plugin
Plugin=WebParser

[MeasureChild2]
Measure=Plugin
Plugin=WebParser

[MeterChild1]
Meter=String

[MeterChild2]
Meter=String
Then you could come in with the Lua script and dynamically add all the measure and meter options, use !CommandMeasure to "Update" the WebParser parent and off you go...
oliver+
Posts: 4
Joined: May 8th, 2014, 10:36 pm

Re: Using LUA to create meters and measures (not whole skins

Post by oliver+ »

Yes i think in my situation (i do not need to allow any number, like 1 million entrys, but maybe 10 -15) this would be the best way.
Thank you for your help.
MikeG621
Posts: 87
Joined: March 18th, 2013, 1:59 pm

Re: Using LUA to create meters and measures (not whole skins

Post by MikeG621 »

You don't need the bare-bones Measure/Meters in the skin to start, that can be generated using !WriteKeyValue; if the item doesn't exist yet (like during the first run) then you can do this:

Code: Select all

(stuff)
;This is the last line
!WriteKeyValue MeterChild1 Meter String
!WriteKeyValue MeterChild1 Text #*MyVar*#

Code: Select all

(stuff)
;This is the last line
[MeterChild1]
Meter=String
Text=#MyVar#
Just have to make sure to call an Update so it re-reads the ini like jsmorley said. I've got a couple skins like this where the skin initially only has meters for the main page, and the Lua script dynamically creates the number of tabs required to switch between the necessary inputs.
User avatar
jsmorley
Developer
Posts: 22629
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Using LUA to create meters and measures (not whole skins

Post by jsmorley »

MikeG621 wrote:You don't need the bare-bones Measure/Meters in the skin to start, that can be generated using !WriteKeyValue; if the item doesn't exist yet (like during the first run) then you can do this:

Code: Select all

(stuff)
;This is the last line
!WriteKeyValue MeterChild1 Meter String
!WriteKeyValue MeterChild1 Text #*MyVar*#

Code: Select all

(stuff)
;This is the last line
[MeterChild1]
Meter=String
Text=#MyVar#
Just have to make sure to call an Update so it re-reads the ini like jsmorley said. I've got a couple skins like this where the skin initially only has meters for the main page, and the Lua script dynamically creates the number of tabs required to switch between the necessary inputs.
Update will not re-read the .ini, only a full Refresh will do that. That was sort of the point of the "minimal measure / meter" approach, using !SetOption to avoid having to "write" the file and refresh. My first answer sorta described the "write / refresh" approach. There are various way to come at this of course.
zealotwarrior
Posts: 1
Joined: May 31st, 2014, 1:35 am

Re: Using LUA to create meters and measures (not whole skins

Post by zealotwarrior »

So I believe my question is related but Im not sure. My understanding is that all meters and measures are static objects. However if we create a new instance of a skin we create new objects each time. In this way using lua scripting to make a whole bunch of active skins could be used to create an array. Am I correct?

My ultimate goal in Rainmeter is to create a file browser so I need an array which can be expanded and contracted without a set number of meters. I am not sure how to do this but it sounds like it could work with scripting.

I have not looked into if we can even get the file names yet but I am still working on the theory.

Thoughts?