It is currently July 27th, 2021, 2:34 pm

Custom [Strike]Skin[\Strike] Context Menu

Tips and Tricks from the Rainmeter Community
User avatar
death.crafter
Posts: 501
Joined: April 24th, 2021, 8:13 pm

Custom [Strike]Skin[\Strike] Context Menu

Post by death.crafter »

I recently skimmed through a topic where the op was asking about a nested context menu. So, I thought why not just make one.

So before diving in a few pros and cons:
Pros:
  • Nested contexts
  • Highly customizable
  • Static or dynamic menu items
Cons:
  • Have to add "Config" parameter to every Bang
  • File paths are relative to the custom menu skin path, naturally(Using #ROOTCONFIGPATH# is preferable)
  • If you want focus from the beginning, to dismiss by clicking else where, you have to use an executable packed with the config
  • Static width of context menu(I may try to find a feasible solution)
Now the real thing:
So all you have to do is to make a script measure and add items to it like you do in Rainmeter section.
So the options go like this:

Code: Select all

[CustomMenu]
Measure=Script
ScriptFile=#ROOTCONFIGPATH#CustomMenu\CustomMenu.lua

; ----------------- Context options
Title1 = <title1>
Option1 = <option1>
Title2 = <title2>
Option2 = <option2>

;; ----------------- Nested context menu
Title3 = <title3>
Title3Subtitle1 = <subcontext3title1>
Title3Option1 = <subcontext3option1>
Title3Subtitle2 = <subcontext3title2>
Title3Option2 = <subcontext3option2>
...
Title3Subtitle6 = <subcontext3title6>
Title3Option6 = <subcontext3option6>
;; -----------------------------------

...

;; ---------------- Divider (Use --- as TitleN)
Title7 = ---
;; -----------------------------------

...

Title15 = <title15>
Option15 = <option15>
UpdateDivider = -1
Yes, max items are 15 and max nested items are 6. But you can overide them by editing the lua and changing the for loops' terminal value.
Now how to call it:

Code: Select all

RightMouseUpAction=[!WriteKeyValue Variables MouseX "([#CURRENTCONFIGX]+$MouseX$)" "#ROOTCONFIGPATH#\CustomMenu\CustomMenu.ini"][!WriteKeyValue Variables MouseY "([#CURRENTCONFIGY]+$MouseY$)" "#ROOTCONFIGPATH#\CustomMenu\CustomMenu.ini"][!ActivateConfig "#ROOTCONFIG#\CustomMenu"]
Make sure to use nested syntax in CURRENTCONFIGX or Y, since it needs to be dynamic.
Now how the hell is it dynamic:
You can just !SetOption and call Initialize(), lol! I don't know the use case tho.
Changing appearance:
Edit the CustomMenu.style file to change the appearance of the menu. All the variables and meter styles are in there. The names are not that confusing.
Example:

Code: Select all

[CustomMenu]
Measure=Script
ScriptFile=CustomMenu\CustomMenu.lua
Title1=Change color to white
Option1=[!SetOption MeterString SolidColor "255,255,255" "#ROOTCONFIG#"][!UpdateMeter MeterString "#ROOTCONFIG#"][!Redraw "#ROOTCONFIG#"]
Title2=Change color to red
Option2=[!SetOption MeterString SolidColor "255,0,0" "#ROOTCONFIG#"][!UpdateMeter MeterString "#ROOTCONFIG#"][!Redraw "#ROOTCONFIG#"]
Title3=Permanent colors
Title3Subtitle1=Blue
Title3Option1=[!WriteKeyValue MeterString SolidColor "0,0,255" "#ROOTCONFIGPATH#CustomContextMenu.ini"][!SetOption MeterString SolidColor "0,0,255" "#ROOTCONFIG#"][!UpdateMeter MeterString "#ROOTCONFIG#"][!Redraw "#ROOTCONFIG#"]
Title3Subtitle2=---
Title3Subtitle3=Pink
Title3Option3=[!WriteKeyValue MeterString SolidColor "255,0,255" "#ROOTCONFIGPATH#CustomContextMenu.ini"][!SetOption MeterString SolidColor "255,0,255" "#ROOTCONFIG#"][!UpdateMeter MeterString "#ROOTCONFIG#"][!Redraw "#ROOTCONFIG#"]
Title4=---
Title5=Log death.crafter
Option5=[!Log "death.crafter"]
Title6=---
Title7=Built-in
Title7Subtitle1=Refresh
Title7Option1=[!Refresh "#ROOTCONFIG#"]
Title7Subtitle2=Skin Menu
Title7Option2=[!SkinMenu "#ROOTCONFIG#"]
Title7Subtitle3=Rainmeter
Title7Option3=[!TrayMenu]
UpdateDivider=-1
Preview of above example(click to animate):
custommenu.gif
Context menu zip:
CustomMenu.zip
Files inside:
CustomMenu.png
Example skin:
CustomMenu_1.0.1.rmskin
If you have trust issues and you want to build them your self: Fixes in 1.0.1
  • Nested context going off screen (thanks Yincognito for pointing out)
You do not have the required permissions to view the files attached to this post.
Last edited by death.crafter on July 21st, 2021, 6:02 pm, edited 1 time in total.
from the Realm of Death
My Current Desktop
User avatar
Active Colors
Moderator
Posts: 807
Joined: February 16th, 2012, 3:32 am
Location: Berlin, Germany

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by Active Colors »

Wow, very nice! I was thinking sometime before about making my own context menu simulation for one of my skins but you've done the job for me. If I find myself implementing it I would let you know :D
User avatar
death.crafter
Posts: 501
Joined: April 24th, 2021, 8:13 pm

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by death.crafter »

Active Colors wrote: July 21st, 2021, 5:48 pm Wow, very nice! I was thinking sometime before about making my own context menu simulation for one of my skins but you've done the job for me. If I find myself implementing it I would let you know :D
I need to update the skin, regarding nested menu going off screen(thanks to Yincognito).

Thanks for the compliment. :-D

Edit: Updated :P
from the Realm of Death
My Current Desktop
User avatar
death.crafter
Posts: 501
Joined: April 24th, 2021, 8:13 pm

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by death.crafter »

Yincognito wrote:
So, I figured out how to solve the problem horizontally, but I can't do so vertically. Can you help me a little out here?

I could have done it if the height of the container were not to be 0 from the beggining. Since I use a formula for the container's height, when I access it on OnRefreshAction, it ends up being 0. I just can't think of another way of getting it from the beggining.

Though I quoted Yincognito, anyone's help is appreciated.

Thanks in advance.
from the Realm of Death
My Current Desktop
User avatar
Yincognito
Rainmeter Sage
Posts: 3644
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by Yincognito »

death.crafter wrote: July 22nd, 2021, 11:57 am So, I figured out how to solve the problem horizontally, but I can't do so vertically. Can you help me a little out here?

I could have done it if the height of the container were not to be 0 from the beggining. Since I use a formula for the container's height, when I access it on OnRefreshAction, it ends up being 0. I just can't think of another way of getting it from the beggining.

Though I quoted Yincognito, anyone's help is appreciated.

Thanks in advance.
I didn't look into your setup in detail yet, but what I can tell is that I had a somewhat similar system of using formulas for the "child skin" (I suppose this is more or less your container, right?) size in my custom tooltip approach, and although I did this exclusively through native Rainmeter, there are a couple of things I did - maybe they can give you an idea regarding solving this:
- I used small !Delay-s to give time to Rainmeter to provide the needed info or do its thing (I'm just mentioning this, mostly it's not needed)
- I used skin-to-skin !SetVariables (didn't use !WriteKeyValue-s at all, btw, much faster using memory than disk) to "communicate" info between skins
- I first updated the meters of the child skin from the parent skin, did a redraw, and only then updated the measure (in my case) that handled the child skin movement (using parent skin specific positioning); I didn't use OnRefreshAction to move the child skin, but a measure, given the dynamic variables and the easiness of controlling it (otherwise the option is theoretically ok, since it runs after the 1st skin update anyway)
- I used an additional variable (1 or 0) passed from the parent skin to the child one to make sure the movement measure from the child skin moved that skin ONLY after it received the "ok" from the variable, meaning the meters from the child skin corrected that skin's position and size accordingly
- in the movement measure, I performed the above variable check in an IfCondition, and moved the skin in the IfTrueAction(s)

In principle, assuming there isn't any other "issue" affecting this, it's about the order of the operations: strict control of that makes sure you first draw the child skin normally, i.e. in its "unmoved" position (easier if that skin is by default hidden, by the way, so you don't see it shifting when displaying it), get the correct info about its position / dimensions, and the last thing you do is to move it in the "final" position.

That being said, it would help if you could pinpoint exactly the key parts that you have a problem with, so I don't have to look for the needle in the haystack in a code I'm not (yet) familiar with. :D

P.S. Sorry for the delay, been doing other "mystery solving" stuff before, LOL. One step at a time for me, it's clearer that way...
User avatar
death.crafter
Posts: 501
Joined: April 24th, 2021, 8:13 pm

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by death.crafter »

Yincognito wrote: July 22nd, 2021, 4:23 pm That being said, it would help if you could pinpoint exactly the key parts that you have a problem with, so I don't have to look for the needle in the haystack in a code I'm not (yet) familiar with. :D
I guess I should have explained better.

So for vertical positioning, here are the variables.
  • [#CURRENTCONFIGY]
  • [PARENT_OPTION:Y] - (where the child context container is supposed to materialize)
  • [CHILD_OPTION_FIRST_ITEM:Y] - (the first no height meter in a child container)
  • [CHILD_OPTION_LAST_ITEM:Y] - (the last no height meter in a child container)
  • [#WORKAREAHEIGHT]
What I am trying to do:
# *{the height of CHILD_CONTAINER}
# **{the distance from end of screen to the parent option}

if *([CHILD_OPTION_LAST_ITEM:Y]-[CHILD_OPTION_LAST_ITEM:Y]) greater than **([#WORKAREAHEIGHT]-[PARENT_OPTION:Y]) then

[PARENT_OPTION:Y]-(([CHILD_OPTION_LAST_ITEM:Y]-[CHILD_OPTION_FIRST_ITEM:Y])-([#WORKAREAHEIGHT]-[PARENT_OPTION:Y]))

And I think I might be able to get it in the mean time.

Thanks for taking your time to reply.
Yincognito wrote: July 22nd, 2021, 4:23 pm P.S. Sorry for the delay, been doing other "mystery solving" stuff before, LOL. One step at a time for me, it's clearer that way...
You don't have to be sorry for such things.
from the Realm of Death
My Current Desktop
User avatar
Yincognito
Rainmeter Sage
Posts: 3644
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by Yincognito »

death.crafter wrote: July 22nd, 2021, 4:58 pm I guess I should have explained better.

So for vertical positioning, here are the variables.
  • [#CURRENTCONFIGY]
  • [PARENT_OPTION:Y] - (where the child context container is supposed to materialize)
  • [CHILD_OPTION_FIRST_ITEM:Y] - (the first no height meter in a child container)
  • [CHILD_OPTION_LAST_ITEM:Y] - (the last no height meter in a child container)
  • [#WORKAREAHEIGHT]
What I am trying to do:
# *{the height of CHILD_CONTAINER}
# **{the distance from end of screen to the parent option}

if *([CHILD_OPTION_LAST_ITEM:Y]-[CHILD_OPTION_LAST_ITEM:Y]) greater than **([#WORKAREAHEIGHT]-[PARENT_OPTION:Y]) then

[PARENT_OPTION:Y]-(([CHILD_OPTION_LAST_ITEM:Y]-[CHILD_OPTION_FIRST_ITEM:Y])-([#WORKAREAHEIGHT]-[PARENT_OPTION:Y]))

And I think I might be able to get it in the mean time.

Thanks for taking your time to reply.



You don't have to be sorry for such things.
What I meant was more of INI / section / option whereabouts, but anyway, I sort of understood what you mean in pseudocode, and found the incriminated place(s) - I was looking in the wrong place up until now. Not a fan of writing stuff from Lua in the INI / INC files behind the user's back at all, much harder to debug and find which is which and which is controlled from where this way, especially if you're not the author.

After trying in vain to write stuff like normal people in the INI-s only to see them overwritten, I tried my best to do a:

Code: Select all

                local containerY = '(#MouseY# < (#SCREENAREAHEIGHT#-(500)) ? ([ContextOption'..i..':Y]) : (#SCREENAREAHEIGHT#-(500)))'
                table.insert(t, '\n[ContextOption'..i..'Background]\nMeter=Shape\nX='..containerX..'\nY='..containerY..'\nColor=Fill Color #SubContextBackgroundColor#\nShape='..rectangle..'\nHidden=1\nGroup=ContextOption'..i..'\nMouseLeaveAction=[!HideMeterGroup ContextOption'..i..'][!Redraw]')
test in your Lua, but while the main menu moved, I have no f...g clue where to move the submenus from. :confused:
User avatar
death.crafter
Posts: 501
Joined: April 24th, 2021, 8:13 pm

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by death.crafter »

Yincognito wrote: July 22nd, 2021, 6:41 pm

Code: Select all

                local containerY = '(#MouseY# < (#SCREENAREAHEIGHT#-(500)) ? ([ContextOption'..i..':Y]) : (#SCREENAREAHEIGHT#-(500)))'
                table.insert(t, '\n[ContextOption'..i..'Background]\nMeter=Shape\nX='..containerX..'\nY='..containerY..'\nColor=Fill Color #SubContextBackgroundColor#\nShape='..rectangle..'\nHidden=1\nGroup=ContextOption'..i..'\nMouseLeaveAction=[!HideMeterGroup ContextOption'..i..'][!Redraw]')
test in your Lua, but while the main menu moved, I have no f...g clue where to move the submenus from. :confused:
Lol I am so sorry for making you work hard.

Just leave it be. I will think of something in the mean time. But even so it will be impossible to fully replicate a context menu. It's just a stand-in after all.

Thanks a lot though.
Since I didn't intend the user to look into the internal workings, I didn't bother with a cleaner code. Somewhat my fault.
from the Realm of Death
My Current Desktop
User avatar
Yincognito
Rainmeter Sage
Posts: 3644
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by Yincognito »

death.crafter wrote: July 22nd, 2021, 7:18 pm Lol I am so sorry for making you work hard.

Just leave it be. I will think of something in the mean time. But even so it will be impossible to fully replicate a context menu. It's just a stand-in after all.

Thanks a lot though.
Since I didn't intend the user to look into the internal workings, I didn't bother with a cleaner code. Somewhat my fault.
Nah, working is not a problem, finding WHAT to work is one, in this case.
This:

Code: Select all

                local containerY = '(#MouseY# < (#SCREENAREAHEIGHT#-(300)) ? ([ContextOption'..i..':Y]) : ([ContextContainer:Y]+[ContextOption'..i..':Y]-([ContextOption7Last:Y]-[ContextOption7Background:Y])))'
                table.insert(t, '\n[ContextOption'..i..'Background]\nMeter=Shape\nX='..containerX..'\nY='..containerY..'\nColor=Fill Color #SubContextBackgroundColor#\nShape='..rectangle..'\nHidden=1\nGroup=ContextOption'..i..'\nMouseLeaveAction=[!HideMeterGroup ContextOption'..i..'][!Redraw]')
will actually work in setting the Y of the child context menu, but there are 2 problems:
- replacing the testing 300 value with the (I think) proper [ContextOption7Last:Y]-[ContextOption7Background:Y] doesn't work
- the background of the child menu will be taller and blank, you probably know better why that happens
These, unless you have a better idea why they happen, might be because things are initially hidden, although I'm not sure why setting the Y works just fine by using the same values (by the way, that Y setting must take the height of a main menu "line"/"item" into account as well, but I had no idea what was that value, so I skipped it)... :???:

P.S. I don't believe in impossible things, that's the rest of the world's opinion. I know for sure things are possible if one really wants so (and, of course, has the brain for it, which you do).
User avatar
death.crafter
Posts: 501
Joined: April 24th, 2021, 8:13 pm

Re: Custom [Strike]Skin[\Strike] Context Menu

Post by death.crafter »

Yincognito wrote: July 22nd, 2021, 7:54 pm - replacing the testing 300 value with the (I think) proper [ContextOption7Last:Y]-[ContextOption7Background:Y] doesn't work
Actually you are setting the Y of ContextOption7Background so you can't use [ContextOption7Background:Y]. For that purpose I made a First item for every child container.

[ContextOption7First:Y] would do the trick if you want to get the height.

But I am not feeling like working on this now. So I will try the above way tomorrow and let you know.
from the Realm of Death
My Current Desktop