Menu with a sub-submenu?

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
V0RT3X
Posts: 249
Joined: 20 May 2023, 21:59
Contact:

Menu with a sub-submenu?

14 Jun 2023, 09:17

Hello, I am working on creating a comprehensive text case converter and am trying to create a menu with submenus that some also have their own sub-submenu. Something similar to the shopped image below.
This is just a small borrowed example script for demonstration. Is what I'm after even possible? I am unable to find reference to this in documentation, or it just isn't making sense to me.

Code: Select all

; Create the popup menu by adding some items to it.
Menu, MyMenu, Add, Item1, MenuHandler
Menu, MyMenu, Add, Item2, MenuHandler
Menu, MyMenu, Add  ; Add a separator line.

; Create another menu destined to become a submenu of the above menu.
Menu, Submenu1, Add, Item1, MenuHandler
Menu, Submenu1, Add, Item2, MenuHandler

; Create a submenu in the first menu (a right-arrow indicator). When the user selects it, the second menu is displayed.
Menu, MyMenu, Add, My Submenu, :Submenu1

Menu, MyMenu, Add  ; Add a separator line below the submenu.
Menu, MyMenu, Add, Item3, MenuHandler  ; Add another menu item beneath the submenu.
return  ; End of script's auto-execute section.

MenuHandler:
MsgBox You selected %A_ThisMenuItem% from the menu %A_ThisMenu%.
return

#z::Menu, MyMenu, Show  ; i.e. press the Win-Z hotkey to show the menu.
 What I'm after...
image.png
image.png (6.25 KiB) Viewed 1124 times
 What I'm working on...
image.png
image.png (15.26 KiB) Viewed 1124 times
User avatar
mikeyww
Posts: 27372
Joined: 09 Sep 2014, 18:38

Re: Menu with a sub-submenu?

14 Jun 2023, 09:42

Code: Select all

#Requires AutoHotkey v1.1.33
Menu, MyMenu  , Add, Item1, MenuHandler
Menu, MyMenu  , Add, Item2, MenuHandler
Menu, MyMenu  , Add
Menu, Submenu2, Add, Item1, MenuHandler
Menu, Submenu2, Add, Item2, MenuHandler
Menu, Submenu1, Add, Item1, MenuHandler
Menu, Submenu1, Add, Item2, MenuHandler
Menu, Submenu1, Add, My Sub Submenu, :Submenu2
Menu, MyMenu  , Add, My Submenu, :Submenu1
Menu, MyMenu  , Add
Menu, MyMenu  , Add, Item3, MenuHandler

#z::Menu, MyMenu, Show

MenuHandler:
MsgBox You selected %A_ThisMenuItem% from the menu %A_ThisMenu%.
Return
User avatar
V0RT3X
Posts: 249
Joined: 20 May 2023, 21:59
Contact:

Re: Menu with a sub-submenu?

14 Jun 2023, 10:52

Thank you. I had not expected it to be so easy. :o
wetware05
Posts: 750
Joined: 04 Dec 2020, 16:09

Re: Menu with a sub-submenu?

14 Jun 2023, 11:07

@V0RT3X already exist several scripts to convert uppercase to lowercase and so on. If you want, I'll share one (or a link) or if you want, make your own version. :thumbup:
wetware05
Posts: 750
Joined: 04 Dec 2020, 16:09

Re: Menu with a sub-submenu?

14 Jun 2023, 11:23

Almost all of those utilities ignore one case: capitalize everything except short or non-significant words. Example: I Don't Want All Words, Like O Or And To Be Capitalized," vs. "I Don't Want all Words, Like or or and to be Capitalized".

This is a routine that mikeyww and TeaDrinker created or improved for this type of case:

Code: Select all

StringLower, Txt, Txt
;IMPORTANT! Change short words to be replaced in the following list according to each language or add more
lowers := ["a", "ha", "el", "él", "y", "pero", "o", "para", "las", "es", "para", "por", "los", "con", "en", "que", "un", "de", "del", "la", "una", "cada", "en", "al", "por", "uno", "mi", "tu", "tú", "no", "ni", "sin", "se", "lo", "e", "su", "sí", "ser", "hay", "tras"]
for k, v in lowers
low .= (k = 1 ? "" : "|") . v
;Txt := RegExReplace(Txt, "(*UCP)(^\b|\b(?!(" . low . ")\b))\w+\b|\b\w+\b$", "$T0") ;other case
;Txt := RegExReplace(Txt, "((?:^|[.!?-]\s+)[a-z])", "$u1") ; and other for English
Txt := RegExReplace(Txt, "(*UCP)(^|\b(?!(" . low . ")\b))\w|(\.|\?|!)\s*\K\w|-\K\w", "$T0") ;valid for Spanish


(You have to create a small base of words to exclude. The current one is for Spanish.)
User avatar
mikeyww
Posts: 27372
Joined: 09 Sep 2014, 18:38

Re: Menu with a sub-submenu?

14 Jun 2023, 12:06

The approach to creating a submenu is the same one that you used in your original script. There are two steps.

1. Create the submenu.
2. Use : to add the submenu to a menu.
User avatar
kunkel321
Posts: 1194
Joined: 30 Nov 2015, 21:19

Re: Menu with a sub-submenu?

14 Jun 2023, 14:23

Related: I found this slick Menu Wizard here on the forum. My apologies to the author.... I didn't save the author name or URL. And now I can't seem to find it with google. ... Kelly found it!
By maestrith
viewtopic.php?t=45649

Code: Select all

#SingleInstance,Force
; For AHK v1 
; By maestrith
; https://www.autohotkey.com/boards/viewtopic.php?t=45649
global Settings:=new XML("Settings"),MainWin:=new GUIKeep(1),MenuXML
if((A_PtrSize=8&&A_IsCompiled="")||!A_IsUnicode){
	SplitPath,A_AhkPath,,dir
	if(!FileExist(correct:=dir "\AutoHotkeyU32.exe")){
		m("Requires AutoHotkey 1.1 to run")
		ExitApp
	}
	Run,"%correct%" "%A_ScriptName%" "%file%",%A_ScriptDir%
	ExitApp
	return
}Main:={"&File":["&New","&Open","Ex&port","Copy To &Clipboard","&Save","E&xit"],"A&bout":["Help","Online Manual"]},Order:=["&File","A&bout"],MenuXML:=new XML("Menu",Settings.Get("//Last/@file","Menus\Menu.XML"))
for a,b in Order
	for c,d in Main[b]
		Menu,% RegExReplace(b,"\W"),Add,%d%,MenuHandler
for a,b in Order
	Menu,Main,Add,%b%,% ":" RegExReplace(b,"\W")
Gui,Menu,Main
MainWin.Add("TreeView,w350 h300 vTV gUpdateColor AltSubmit,,wh"
		 ,"GroupBox,w240 h140 Section,New Menu:,y"
		 ,"Edit,xp+10 yp+20 w220 vItem,,y"
		 ,"Button,xs+10 yp+30 gAddMenuItem Default,&Add,y"
		 ,"Button,x+m gAddSubMenuItem,Add &Sub-Menu,y"
		 ,"Button,x+m gEdit,&Edit,y"
		 ,"Radio,xs+10 yp+35 vAfter Checked gFocusItem,Insert Af&ter,y"
		 ,"Radio,vBefore gFocusItem,Insert &Before,y"
		 ,"GroupBox,xs+250 ys w100 h110 Section,Color,y"
		 ,"Progress,xs+10 ys+20 w16 h16 c0xff00ff vProgress,100,y"
		 ,"Button,xs+10 yp+20 gChangeColor,&Current,y"
		 ,"Button,gChangeRoot,&Root,y"
		 ,"Button,xm gShowMenu,Sho&w Menu,y"
		 ,"Checkbox,vConfirm,Confirm Delete,y"
		 ,"Button,gHelp,Help,y"
		 ,"StatusBar")
MainWin.SetText("Confirm",Settings.Get("//Confirm",1))
MainWin.Show("Menu Maker")
Hotkey,IfWinActive,% MainWin.ID
for a,b in {Delete:"Delete",Up:"Arrows",Down:"Arrows",Left:"Arrows",Right:"Arrows","!Up":"Move","!Down":"Move","!Left":"Move","!Right":"Move"}
	Hotkey,%a%,%b%,On
Populate(),MainWin.Focus("Item")
return
class GUIKeep{
	static Table:=[],ShowList:=[]
	__Get(x*){
		if(x.1)
			return this.Var[x.1]
		return this.Add()
	}__New(win,parent:=""){
		DetectHiddenWindows,On
		Gui,%win%:Destroy
		Gui,%win%:+hwndhwnd -DPIScale
		Gui,%win%:Margin,5,5
		Gui,%win%:Font,s10 c0xAAAAAA,Courier New
		Gui,%win%:Color,0,0
		this.All:=[],this.gui:=[],this.hwnd:=hwnd,this.con:=[],this.XML:=new XML("GUI"),this.ahkid:=this.id:="ahk_id" hwnd,this.win:=win,this.Table[win]:=this,this.var:=[],this.Radio:=[],this.Static:=[]
		for a,b in {border:A_OSVersion~="^10"?3:0,caption:DllCall("GetSystemMetrics",int,4,"int")}
			this[a]:=b
		Gui,%win%:+LabelGUIKeep.
		Gui,%win%:Default
		return this
	}Add(info*){
		static
		if(!info.1){
			var:=[]
			Gui,% this.Win ":Submit",Nohide
			for a,b in this.var{
				if(b.Type="s")
					Var[a]:=b.sc.GetUNI()
				else
					var[a]:=%a%
			}return var
		}for a,b in info{
			i:=StrSplit(b,","),newpos:=""
			if(i.1="ComboBox")
				WinGet,ControlList,ControlList,% this.ID
			if(i.1="s"){
				Pos:=RegExReplace(i.2,"OU)\s*\b(v.+)\b")
				sc:=new s(1,{Pos:Pos}),hwnd:=sc.sc
			}else
				Gui,% this.win ":Add",% i.1,% i.2 " hwndhwnd",% i.3
			if(RegExMatch(i.2,"U)\bg(.*)\b",Label))
				Label:=Label1
			if(RegExMatch(i.2,"U)\bv(.*)\b",var))
				this.var[var1]:={hwnd:HWND,type:i.1,sc:sc}
			this.con[hwnd]:=[]
			if(i.4!="")
				this.con[hwnd,"pos"]:=i.4,this.resize:=1
			if(i.5)
				this.Static.Push(hwnd)
			Name:=Var1?Var1:Label
			if(i.1="ListView"||i.1="TreeView")
				this.All[Name]:={HWND:HWND,Name:Name,Type:i.1,ID:"ahk_id" HWND}
			if(i.1="ComboBox"){
				WinGet,ControlList2,ControlList,% this.ID
				Obj:=StrSplit(ControlList2,"`n"),LeftOver:=[]
				for a,b in Obj
					LeftOver[b]:=1
				for a,b in Obj2:=StrSplit(ControlList,"`n")
					LeftOver.Delete(b)
				for a in LeftOver{
					if(!InStr(a,"ComboBox")){
						ControlGet,Married,HWND,,%a%,% this.ID
						this.XML.Add("Control",{hwnd:Married,id:"ahk_id" Married+0,name:Name,type:"Edit"},,1)
					}
				}
				
			}
			this.XML.Add("Control",{hwnd:HWND,id:"ahk_id" HWND,name:Name,type:i.1},,1)
	}}Close(a:=""){
		this:=GUIKeep.table[A_Gui]
		if(A_Gui=1)
			this.Exit()
	}ContextMenu(x*){
		if(IsFunc(Function:=A_Gui "GuiContextMenu"))
			%Function%(x*)
	}Current(XPath,Number){
		Node:=Settings.SSN(XPath)
		all:=SN(Node.ParentNode,"*")
		while(aa:=all.item[A_Index-1])
			(A_Index=Number?aa.SetAttribute("last",1):aa.RemoveAttribute("last"))
	}Default(Name:=""){
		Gui,% this.Win ":Default"
		ea:=this.XML.EA("//Control[@name='" Name "']")
		if(ea.Type~="TreeView|ListView")
			Gui,% this.Win ":" ea.Type,% ea.HWND
	}DisableAll(){
		for a,b in this.All{
			GuiControl,1:+g,% b.HWND
			GuiControl,1:-Redraw,% b.HWND
		}
	}DropFiles(filelist,ctrl,x,y){
		df:="DropFiles"
		if(IsFunc(df))
			%df%(filelist,ctrl,x,y)
	}EnableAll(){
		for a,b in this.All{
			GuiControl,% this.Win ":+g" b.Name,% b.HWND
			GuiControl,% this.Win ":+Redraw",% b.HWND
		}
	}Escape(){
		KeyWait,Escape,U
		if(A_Gui!=1)
			Gui,%A_Gui%:Destroy
		else
			MainWin.Exit()
		return 
	}Exit(){
		Exit:
		Info:=MainWin[]
		if(A_Gui=1){
			Node:=GetNode(),Node.SetAttribute("last",1),MenuXML.Save(1)
			Settings.Add("Last",{file:MenuXML.File}),Settings.Add("Confirm",,MainWin[].Confirm)
			MainWin.SavePos()
			Settings.Save(1)
			ExitApp
		}else
			Gui,% this.Win ":Destroy"
		return
	}Focus(Control){
		this.Default(Control)
		ControlFocus,,% this.GetCtrlXML(Control,"id")
	}GetCtrl(Name,Value:="hwnd"){
		return this.All[Name]
	}GetCtrlXML(Name,Value:="hwnd"){
		return Info:=this.XML.SSN("//*[@name='" Name "']/@" Value).text
	}GetPos(){
		Gui,% this.win ":Show",AutoSize Hide
		WinGet,cl,ControlListHWND,% this.ahkid
		SysGet,Menu,55
		pos:=this.winpos(),ww:=pos.w,wh:=pos.h,flip:={x:"ww",y:"wh"}
		for index,hwnd in StrSplit(cl,"`n"){
			obj:=this.gui[hwnd]:=[]
			ControlGetPos,x,y,w,h,,ahk_id%hwnd%
			y-=Menu
			for c,d in StrSplit(this.con[hwnd].pos)
				d~="w|h"?(obj[d]:=%d%-w%d%):d~="x|y"?(obj[d]:=%d%-(d="y"?wh+this.Caption+this.Border:ww+this.Border))
		}
		Gui,% this.win ":+MinSize400x400"
	}Map(Location,Info:=""){
		static Map:={PopulateAccounts:["PopulateAccounts"],PopulateAllFilters:["PopulateMGList"],PopulateMGList:["PopulateMGList"]
				  ,PopulateMGListItems:["PopulateMGListItems"],PopulateMGTags:["PopulateMGTags"],PopulateMGMessages:["PopulateMGMessages"]}
		if(!Map[Location])
			return m("Working on: " Location,ExtraInfo.1,ExtraInfo.2)
		this.DisableAll()
		for a,b in Map[Location]{
			if(b.1="Fix")
				return m("Work On: " a)
			MainWin.Busy:=1,MainWin.Function:=b.1?b.1:b
			Info:=%b%(Info)
			if(Info.tv){
				TV_Modify(Info.tv,"Select Vis Focus")
			}
			while(MainWin.Busy){
				t("It's busy",A_TickCount,MainWin.Function,"Hmm.")
			}
		}this.EnableAll()
		return Info
	}SavePos(){
		if(!top:=Settings.SSN("//gui/position[@window='" this.win "']"))
			top:=Settings.Add("gui/position",{window:this.Win},,1)
		top.text:=this.WinPos().text
	}SetText(Control,Text:=""){
		if((sc:=this.Var[Control].sc).sc)
			Len:=VarSetCapacity(tt,StrPut(Text,"UTF-8")-1),StrPut(Text,&tt,Len,"UTF-8"),sc.2181(0,&tt)
		else
			GuiControl,% this.Win ":",% this.GetCtrlXML(Control),%Text%
	}Show(name){
		this.GetPos(),Pos:=this.Resize=1?"":"AutoSize",this.name:=name
		if(this.resize=1)
			Gui,% this.win ":+Resize"
		GUIKeep.ShowList.Push(this)
		SetTimer,GUIKeepShow,-100
		return
		GUIKeepShow:
		while(this:=GUIKeep.ShowList.Pop()){
			Gui,% this.win ":Show",% Settings.SSN("//gui/position[@window='" this.win "']").text " " pos,% this.name
			this.size()
			if(this.resize!=1){
				Gui,% this.win ":Show",AutoSize
			}
			WinActivate,% this.id
		}
		return
	}Size(){
		this:=GUIKeep.table[A_Gui],pos:=this.winpos()
		for a,b in this.gui
			for c,d in b
				GuiControl,% this.win ":MoveDraw",%a%,% c (c~="y|h"?pos.h:pos.w)+d
	}WinPos(HWND:=0){
		VarSetCapacity(rect,16),DllCall("GetClientRect",ptr,(HWND?HWND:this.hwnd),ptr,&rect)
		WinGetPos,x,y,,,% (HWND?"ahk_id" HWND:this.ahkid)
		w:=NumGet(rect,8,"int"),h:=NumGet(rect,12,"int"),text:=(x!=""&&y!=""&&w!=""&&h!="")?"x" x " y" y " w" w " h" h:""
		return {x:x,y:y,w:w,h:h,text:text}
	}
}
Exit(){
	Settings.Save(1)
}
MenuHandler(a,b,c){
	Item:=Clean(a)
	if(c="File"){
		if(Item="Exit"){
			MainWin.Exit()
			ExitApp
		}else if(Item="Save"){
			if(MenuXML.File="Menus\Menu.xml"){
				if(!FileExist(A_ScriptDir "\Menus"))
					FileCreateDir,%A_ScriptDir%\Menus
				FileSelectFile,FileName,S16,%A_ScriptDir%\Menus,Save,*.xml
				if(ErrorLevel)
					return
				FileName:=SubStr(FileName,-3)!=".xml"?FileName.=".xml":FileName
				MenuXML.File:=FileName,MenuXML.Save(1)
				return
			}else
				return MenuXML.Save(1)
		}else if(Item="New"){
			return MenuXML:=new XML("Menu","Menus\Menu.xml"),MenuXML.XML.LoadXML("<Menu/>"),Populate()
		}else if(Item="Open"){
			FileSelectFile,FileName,,Menus,Open a Menu,*.xml
			if(ErrorLevel||!FileExist(FileName))
				return
			xx:=new XML("Menu",FileName)
			if(!xx.SSN("//*[not(Menu) or not(Item)]"))
				return m("XML Not compatible")
			return MenuXML:=xx,Populate()
		}else if(Item="Export")
			return Export()
		else if(Item="Copy_To_Clipboard")
			return Clipboard:=Export(1),m("Code Coppied to Clipboard")
	}if(c="About"){
		if(Item="Help")
			return Help()
		else if(Item="Online_Manual")
			return m("Coming soon")
	}
	m("Coming Soon...")
}
ShowMenu(){
	All:=MenuXML.SN("//Menu/descendant::*")
	while(aa:=All.Item[A_Index-1],ea:=XML.EA(aa)){
		Parent:=aa.ParentNode,ParentName:=SSN(Parent,"@name").text,ParentName:=ParentName?ParentName:"Menu"
		Menu,%ParentName%,Add,% ea.Name,DeadEnd
	}while(aa:=All.Item[A_Index-1],ea:=XML.EA(aa)){
		Parent:=aa.ParentNode,ParentName:=SSN(Parent,"@name").text,ParentName:=ParentName?ParentName:"Menu"
		if(SSN(aa,"*").NodeName="Item"){
			if(Color:=SSN(aa,"Item")?ea.Color:SSN(aa.ParentNode,"@color").text){
				Menu:=SSN(aa,"Item")?ea.Name:SSN(aa.ParentName,"@name").text
				Menu:=Menu?Menu:"Menu"
				Menu,%Menu%,Color,% RGB(Color)
			}
			Menu,%ParentName%,Add,% ea.Name,% ":" ea.Name
	}}if(Color:=MenuXML.SSN("//Menu/@color").text)
		Menu,Menu,Color,% RGB(Color),Single
	Menu,Menu,Show
}
Clean(Text){
	return RegExReplace(RegExReplace(Text," ","_"),"\W")
}
Populate(SetLast:=0){
	if(SetLast)
		GetNode().SetAttribute("last",1)
	MainWin.Default("TV")
	GuiControl,1:-Redraw,SysTreeView321
	TV_Delete(),All:=MenuXML.SN("//Menu/descendant::*")
	while(aa:=All.Item[A_Index-1],ea:=XML.EA(aa))
		aa.SetAttribute("tv",TV_Add(ea.Name,SSN(aa.ParentNode,"@tv").text))
	if(Last:=MenuXML.SSN("//*[@last]"))
		TV_Modify(SSN(Last,"@tv").text,"Select Vis Focus"),Last.RemoveAttribute("last")
	All:=MenuXML.SN("//*[@expand]")
	while(aa:=All.Item[A_Index-1],ea:=XML.EA(aa))
		TV_Modify(ea.tv,"Expand"),aa.RemoveAttribute("expand")
	GuiControl,1:+Redraw,SysTreeView321
}
GetNode(){
	MainWin.Default("TV")
	return Node:=MenuXML.SSN("//*[@tv='" TV_GetSelection() "']")
}
AddMenuItem(){
	Obj:=MainWin[],Item:=Obj.Item
	if(ErrorLevel||!Item)
		return
	if(!Node:=GetNode())
		return MenuXML.Add("Menu/Item",{name:Item,last:1}),Populate(),MainWin.SetText("Item")
	FindDupe(Node,Item)
	New:=MenuXML.Add("Item",{name:Item,last:1},,1)
	if(Obj.Before)
		Node.ParentNode.InsertBefore(New,Node)
	else if(Obj.After){
		if(Next:=Node.NextSibling)
			Node.ParentNode.InsertBefore(New,Next)
		else
			Node.ParentNode.AppendChild(New)
	}MainWin.SetText("Item"),Populate()
}
AddSubMenuItem(){
	Item:=MainWin[].Item
	if(ErrorLevel||!Item)
		return
	if(!Node:=GetNode())
		return MenuXML.Add("Menu/Item",{name:Item,last:1}),Populate()
	FindDupe(Node.FirstChild,Item)
	if(MenuXML.Find(Node,"Item/@name",Item))
		return m("Menu already exists")
	New:=MenuXML.Under(Node,"Item",{name:Item,last:1}),Populate(),MainWin.SetText("Item")
}
Delete(){
	Node:=GetNode(),Confirm:=MainWin[].Confirm
	if(Confirm)
		if(m("Can not be undone, are you sure?","ico:?","btn:ync","def:2")!="Yes")
			return
	if(!Next:=Node.NextSibling?Node.NextSibling:Node.PreviousSibling)
		Next:=Node.ParentNode
	Next.SetAttribute("last",1),Node.ParentNode.RemoveChild(Node),Populate()
}
Arrows(){
	ControlGetFocus,Focus,% MainWin.ID
	if(Focus="Edit1")
		ControlSend,SysTreeView321,{%A_ThisHotkey%},% MainWin.ID
	else
		Send,{%A_ThisHotkey%}
}
Edit(){
	Node:=GetNode()
	InputBox,Item,New Menu Item Name,Enter the new name for this menu item,,,,,,,,% (Name:=SSN(Node,"@name").text)
	if(ErrorLevel||!Item||Name=Item)
		return
	FindDupe(Node,Item),Node.SetAttribute("name",Item),Populate(1)
}
FindDupe(Node,Item){
	if(SSN(Node.ParentNode,"Item[translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='" Format("{:L}",Item) "']")){
		m("Menu Item Already Exists")
		Exit
	}
}
Move(){
	Node:=GetNode()
	if((Direction:=A_ThisHotkey)="!Up"){
		if(Next:=Node.PreviousSibling)
			Next.ParentNode.InsertBefore(Node,Next),Populate(1)
	}else if(Direction="!Down"){
		if(Next:=Node.NextSibling.NextSibling)
			Next.ParentNode.InsertBefore(Node,Next),Populate(1)
		else
			Node.ParentNode.AppendChild(Node),Populate(1)
	}else if(Direction="!Left"){
		if((Parent:=Node.ParentNode.ParentNode).NodeName!="#document")
			Parent.AppendChild(Node),Populate(1)
	}else if(Direction="!Right"){
		if(Under:=Node.NextSibling)
			Under.AppendChild(Node),Populate(1)
	}
}
Help(){
	m("Press Alt+Up/Down/Left/Right to move menu items")
}
m(x*){
	static list:={btn:{oc:1,ari:2,ync:3,yn:4,rc:5,ctc:6},ico:{"x":16,"?":32,"!":48,"i":64}},msg:=[]
	static Title
	list.title:="Menu Maker",list.def:=0,list.time:=0,value:=0,txt:=""
	WinGetTitle,Title,A
	for a,b in x
		obj:=StrSplit(b,":"),(vv:=List[obj.1,obj.2])?(value+=vv):(list[obj.1]!="")?(List[obj.1]:=obj.2):txt.=b "`n"
	msg:={option:value+262144+(list.def?(list.def-1)*256:0),title:list.title,time:list.time,txt:txt}
	Sleep,120
	MsgBox,% msg.option,% msg.title,% msg.txt,% msg.time
	for a,b in {OK:value?"OK":"",Yes:"YES",No:"NO",Cancel:"CANCEL",Retry:"RETRY"}
		IfMsgBox,%a%
			return b
	return
}
DeadEnd(a,b,c){
	m("You Clicked: " a,"In Menu: " c)
}
ChangeColor(){
	Node:=GetNode()
	if(!SSN(Node,"Item"))
		Node:=Node.ParentNode
	Dlg_Color(Node,,MainWin.HWND),UpdateColor()
}
Dlg_Color(Node,Default:="",hwnd:="",Attribute:="color"){
	static
	Active:=DllCall("GetActiveWindow")
	Node:=Node.xml?Node:Settings.Add(Trim(Node,"/")),Default:=Default?Default:Settings.SSN("//default"),Color:=(((Color:=SSN(Node,"@" Attribute).text)!="")?Color:SSN(Default,"@" Attribute).text)
	VarSetCapacity(Custom,16*4,0),size:=VarSetCapacity(ChooseColor,9*4,0)
	for a,b in Settings.EA("//CustomColors")
		NumPut(Round(b),Custom,(A_Index-1)*4,"UInt")
	NumPut(size,ChooseColor,0,"UInt"),NumPut(hwnd,ChooseColor,4,"UPtr"),NumPut(Color,ChooseColor,3*4,"UInt"),NumPut(3,ChooseColor,5*4,"UInt"),NumPut(&Custom,ChooseColor,4*4,"UPtr")
	ret:=DllCall("comdlg32\ChooseColorW","UPtr",&ChooseColor,"UInt")
	CustomColors:=Settings.Add("CustomColors")
	Loop,16
		CustomColors.SetAttribute("Color" A_Index,NumGet(Custom,(A_Index-1)*4,"UInt"))
	if(!ret)
		Exit
	Node.SetAttribute(Attribute,(Color:=NumGet(ChooseColor,3*4,"UInt")))
	if(!Node.xml)
		m("Bottom of Dlg_Color()",Node.xml,Color)
	WinActivate,ahk_id%Active%
	return Color
}
RGB(c){
	return Format("0x{:06X}",(c&255)<<16|c&65280|c>>16)
}
DynaRun(Script,Wait:=true,name:="Untitled"){
	static exec,started,filename
	if(!IsObject(v.Running))
		v.Running:=[]
	filename:=name,MainWin.Size(),exec.Terminate()
	if(Script~="i)m(.*)\{"=0)
		Script.="`n" "m(x*){`nfor a,b in x`nlist.=b Chr(10)`nMsgBox,,AHK Studio,% list`n}"
	if(Script~="i)t(.*)\{"=0)
		Script.="`n" "t(x*){`nfor a,b in x`nlist.=b Chr(10)`nToolTip,% list`n}"
	shell:=ComObjCreate("WScript.Shell"),exec:=shell.Exec("AutoHotkey.exe /ErrorStdOut *"),exec.StdIn.Write(Script),exec.StdIn.Close(),started:=A_Now
	v.Running[Name]:=exec
	return
}
Export(Return:=0){
	All:=MenuXML.SN("//Menu/descendant::*")
	while(aa:=All.Item[A_Index-1],ea:=XML.EA(aa))
		Parent:=aa.ParentNode,ParentName:=SSN(Parent,"@name").text,ParentName:=ParentName?ParentName:"Menu",Script.="Menu," ParentName ",Add," ea.Name ",Function`r`n"
	while(aa:=All.Item[A_Index-1],ea:=XML.EA(aa)){
		Parent:=aa.ParentNode,ParentName:=SSN(Parent,"@name").text,ParentName:=ParentName?ParentName:"Menu"
		if(SSN(aa,"*").NodeName="Item"){
			if(Color:=SSN(aa,"Item")?ea.Color:SSN(aa.ParentNode,"@color").text)
				Menu:=SSN(aa,"Item")?ea.Name:SSN(aa.ParentName,"@name").text,Menu:=Menu?Menu:"Menu",Script.="Menu," Menu ",Color," RGB(Color) "`r`n"
			Script.="Menu," ParentName ",Add," ea.Name ",:" ea.Name "`r`n"
	}}if(Color:=MenuXML.SSN("//Menu/@color").text)
		Script.="Menu,Menu,Color," RGB(Color) ",Single`r`n"
	Script.="Menu,Menu,Show`r`nreturn`r`nFunction(Item,Index,Menu){`r`n`tMsgBox,You Clicked: %Item% Under: %Menu%`r`n}`r`nreturn"
	if(Return)
		return Script
	FileSelectFile,FileName,S16,,Export FileName,*.ahk
	File:=FileOpen(FileName,"RW"),File.Write(Script),File.Length(File.Position),File.Close()
	Run,%FileName%
}
UpdateColor(){
	Node:=GetNode()
	Color:=SSN(Node,"Item")?SSN(Node,"@color").text:SSN(Node.ParentNode,"@color").text
	GuiControl,% "1:+c" RGB(Color),% MainWin.GetCtrlXML("Progress")
}
ChangeRoot(){
	Node:=MenuXML.SSN("//Menu"),Dlg_Color(Node,,MainWin.HWND)
}
FocusItem(){
	MainWin.Focus("Item")
}
Class XML{
	keep:=[]
	__Get(x=""){
		return this.XML.xml
	}__New(param*){
		if(!FileExist(A_ScriptDir "\lib"))
			FileCreateDir,%A_ScriptDir%\lib
		root:=param.1,file:=param.2,file:=file?file:root ".xml",temp:=ComObjCreate("MSXML2.DOMDocument"),temp.SetProperty("SelectionLanguage","XPath"),this.XML:=temp,this.file:=file,XML.keep[root]:=this
		if(Param.3)
			temp.preserveWhiteSpace:=1
		if(FileExist(file)){
			ff:=FileOpen(file,"R","UTF-8"),info:=ff.Read(ff.Length),ff.Close()
			if(info=""){
				this.XML:=this.CreateElement(temp,root)
				FileDelete,%file%
			}else
				temp.LoadXML(info),this.XML:=temp
		}else
			this.XML:=this.CreateElement(temp,root)
		SplitPath,file,,dir
		if(!FileExist(dir))
			FileCreateDir,%dir%
	}Add(XPath,att:="",text:="",dup:=0){
		p:="/",add:=(next:=this.SSN("//" XPath))?1:0,last:=SubStr(XPath,InStr(XPath,"/",0,0)+1)
		if(!next.xml){
			next:=this.SSN("//*")
			for a,b in StrSplit(XPath,"/")
				p.="/" b,next:=(x:=this.SSN(p))?x:next.AppendChild(this.XML.CreateElement(b))
		}if(dup&&add)
			next:=next.ParentNode.AppendChild(this.XML.CreateElement(last))
		for a,b in att
			next.SetAttribute(a,b)
		if(text!="")
			next.text:=text
		return next
	}CreateElement(doc,root){
		return doc.AppendChild(this.XML.CreateElement(root)).ParentNode
	}EA(XPath,att:=""){
		list:=[]
		if(att)
			return XPath.NodeName?SSN(XPath,"@" att).text:this.SSN(XPath "/@" att).text
		nodes:=XPath.NodeName?XPath.SelectNodes("@*"):nodes:=this.SN(XPath "/@*")
		while(nn:=nodes.item[A_Index-1])
			list[nn.NodeName]:=nn.text
		return list
	}Find(info*){
		static last:=[]
		doc:=info.1.NodeName?info.1:this.xml
		if(info.1.NodeName)
			node:=info.2,find:=info.3,return:=info.4!=""?"SelectNodes":"SelectSingleNode",search:=info.4
		else
			node:=info.1,find:=info.2,return:=info.3!=""?"SelectNodes":"SelectSingleNode",search:=info.3
		if(InStr(info.2,"descendant"))
			last.1:=info.1,last.2:=info.2,last.3:=info.3,last.4:=info.4
		if(InStr(find,"'"))
			return doc[return](node "[.=concat('" RegExReplace(find,"'","'," Chr(34) "'" Chr(34) ",'") "')]/.." (search?"/" search:""))
		else
			return doc[return](node "[.='" find "']/.." (search?"/" search:""))
	}Get(XPath,Default){
		text:=this.SSN(XPath).text
		return text?text:Default
	}ReCreate(XPath,new){
		rem:=this.SSN(XPath),rem.ParentNode.RemoveChild(rem),new:=this.Add(new)
		return new
	}Save(x*){
		if(x.1=1)
			this.Transform()
		if(this.XML.SelectSingleNode("*").xml="")
			return m("Errors happened while trying to save " this.file ". Reverting to old version of the XML")
		FileName:=this.file?this.file:x.1.1,ff:=FileOpen(FileName,"R"),text:=ff.Read(ff.length),ff.Close()
		if(ff.encoding!="UTF-8")
			FileDelete,%FileName%
		if(!this[])
			return m("Error saving the " this.file " XML.  Please get in touch with maestrith if this happens often")
		if(!FileExist(FileName))
			FileAppend,% this[],%FileName%,UTF-8
		else if(text!=this[])
			file:=FileOpen(FileName,"W","UTF-8"),file.Write(this[]),file.Length(file.Position),file.Close()
	}SSN(XPath){
		return this.XML.SelectSingleNode(XPath)
	}SN(XPath){
		return this.XML.SelectNodes(XPath)
	}Transform(Loop:=1){
		static
		if(!IsObject(xsl))
			xsl:=ComObjCreate("MSXML2.DOMDocument"),xsl.loadXML("<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""><xsl:output method=""xml"" indent=""yes"" encoding=""UTF-8""/><xsl:template match=""@*|node()""><xsl:copy>`n<xsl:apply-templates select=""@*|node()""/><xsl:for-each select=""@*""><xsl:text></xsl:text></xsl:for-each></xsl:copy>`n</xsl:template>`n</xsl:stylesheet>"),style:=null
		Loop,%Loop%
			this.XML.TransformNodeToObject(xsl,this.xml)
	}Under(under,node,att:="",text:="",list:=""){
		new:=under.AppendChild(this.XML.CreateElement(node)),new.text:=text
		for a,b in att
			new.SetAttribute(a,b)
		for a,b in StrSplit(list,",")
			new.SetAttribute(b,att[b])
		return new
	}
}
SSN(node,XPath){
	return node.SelectSingleNode(XPath)
}
SN(node,XPath){
	return node.SelectNodes(XPath)
}
t(x*){
	for a,b in x{
		if((obj:=StrSplit(b,":")).1="time"){
			SetTimer,killtip,% "-" obj.2*1000
			Continue
		}
		list.=b "`n"
	}
	Tooltip,% list
	return
	killtip:
	ToolTip
	return
}
Last edited by kunkel321 on 20 Jun 2023, 08:13, edited 1 time in total.
ste(phen|ve) kunkel
User avatar
V0RT3X
Posts: 249
Joined: 20 May 2023, 21:59
Contact:

Re: Menu with a sub-submenu?

14 Jun 2023, 19:31

Wow and thank you everyone!! @mikeyww's first reply gave me what I was missing. I just wasn't seeing it until spoon fed. :oops:
@wetware05, thank you for the offer. I had already done several searches for ideas, and this was just me trying to put everything together mostly to get a better understanding. Much easier for me that trying to pull it out of documentation text. Never have been good at that. I figured if I was going to attempt this case converter, I should at least pack some extras in. Thus, the sub-submenus came to mind so I could keep the main menu shorter and only expand the extras as needed. Of course it now spreads horizontally when fully expanded, but it works and that's all I can ask for. Can post the script if anyone has an interest, but as noted, there are plenty out there.
Now to look at this Menu Wizard that @kunkel321 has put on my radar...

Code: Select all

/*
Text Case Converter Plus+
 ╞═══════════✏ Notes ✏═══════════╡ 
» Light mode on by default.
» *TempText is just whats been selected/copied.
» ** If you have a case where you DONT want TempText to be pasted (like for the date Case), just put  Exit  at the end of it so it Exits the process instead of continuing down and pasting TempText (putting Exit makes it not paste TempText)

; ◦ ◦ ◦ ◦ ◦ ◦ ◦ Base Script Notes ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
» Refresh Script ════  Ctrl + HOME key rapidly clicked 2 times. (# TapCounts)
» Exit Script ════════  Ctrl + Escape key rapidly clicked 3 times. (# TapCounts)

» Script Updater: Auto-reload script upon saved changes.
    ─ If you make any changes to the script file and save it, the script will automatically reload itself and continue running without manual intervention.
 ╞────────✏ Notes End ✏────────╡ 
*/

; ╞═══════════ Auto-Execute ═══════════╡ 
Gosub, AutoExecute

; ╞──────── Auto-Execute End ────────╡ 

; ╞───────────── MENUS ───────────────╡

GroupAdd All

; Menu Case, Add, • • • • • • • • • • • •,  CCase 
Menu Case, Add 
 Menu Case, Color, D6F1FF
Menu Case, Add, &1 UPPERCASE, CCase 
Menu Case, Add, &2 lowercase, CCase 
Menu Case, Add, &3 Title Case, CCase 
Menu Case, Add, &4 Sentence case, CCase 
Menu Case, Add, &5 iNVERT cASE, CCase 
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Adds, Add  
Menu Adds, Color, D1FFF0
Menu Adds, Add, Insert Date (MM/DD/YY), CCase 
Menu Adds, Add, Insert Degree Symbol (°), CCase 
Menu Adds, Add 
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ ; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Cases Insert, Add
Menu Cases Insert, Add, raNDoM cASE, CCase 
Menu Cases Insert, Add, Reverse Case - esaC esreveR, CCase 
Menu Cases Insert, Add, SpOnGeBoB cAsE, CCase
Menu Cases Insert, Add, S p r e a d  T e x t  C a s e, CCase 
Menu Adds, Add, Other Cases: , :Cases Insert 	 ; ←←← OTHER CASES HEADER.
Menu Case, Add, Additionals: , :Adds 		 ; ←←← ADDITIONALS HEADER.
Menu Cases Insert, Add
Menu Adds, Add
Menu Case, Add 
Menu Cases Insert, Color, FFF8C7
Menu Insert, Add
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Arrow, Add
Menu Arrow, Color, FFF8C7
Menu Arrow, Add, Insert Up Arrow (↑), CCase
Menu Arrow, Add, Insert Down Arrow (↓), CCase
Menu Arrow, Add, Insert Left Arrow (←), CCase
Menu Arrow, Add, Insert Right Arrow (→), CCase
Menu Arrow, Add
Menu Arrow, Add, Insert Horizontal Arrow (↔), CCase
Menu Arrow, Add, Insert Verticle Arrow (↕), CCase
Menu Arrow, Add
Menu Arrow, Add, Insert UpLeft Arrow (↖), CCase
Menu Arrow, Add, Insert UpRight Arrow (↗), CCase
Menu Arrow, Add, Insert DownRight Arrow (↘), CCase
Menu Arrow, Add, Insert DownLeft Arrow (↙), CCase
Menu Arrow, Add
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Bullet, Add
Menu Bullet, Color, FFF8C7
Menu Bullet, Add, Insert Big Dot Bullet (●), CCase
Menu Bullet, Add, Insert Small Dot Bullet (•), CCase
Menu Bullet, Add, Insert Big Square Bullet (■), CCase
Menu Bullet, Add, Insert Small Square Bullet (▪), CCase
Menu Bullet, Add
Menu Bullet, Add, Insert Big Empty Square Bullet (☐), CCase
Menu Bullet, Add, Insert Small Empty Square Bullet (▫), CCase
Menu Bullet, Add, Insert Big EmptyDot Bullet (○), CCase
Menu Bullet, Add, Insert Small Empty Dot Bullet (◦), CCase
Menu Bullet, Add
Menu Bullet, Add, Insert Black Diamond Bullet (◆), CCase
Menu Bullet, Add, Insert Empty Diamond  Bullet (◇), CCase
Menu Bullet, Add, Insert Centered Diamond Bullet (◈), CCase
Menu Bullet, Add
Menu Bullet, Add, Insert Black Diamond Star Bullet (✦), CCase
Menu Bullet, Add, Insert Empty Diamond Star Bullet (✧), CCase
Menu Bullet, Add
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Encloser, Add
Menu Encloser, Color, FFF8C7
Menu Encloser, Add, Insert ″…″ Quotes, CCase
Menu Encloser, Add, Insert '…' Apostrophes, CCase 
Menu Encloser, Add, Insert `*…* Asterisks, CCase
Menu Encloser, Add
Menu Encloser, Add, Insert (…) Parentheses, CCase 
Menu Encloser, Add, Insert `[…] Square Brackets, CCase
Menu Encloser, Add, Insert `{…} Curly Brackets, CCase
Menu Encloser, Add
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu 8ths, Add
Menu 8ths, Color, FFF8C7
Menu 8ths, Add, Insert (⅛), CCase
Menu 8ths, Add, Insert (¼), CCase
Menu 8ths, Add, Insert (⅜), CCase
Menu 8ths, Add, Insert (½), CCase
Menu 8ths, Add, Insert (⅝), CCase
Menu 8ths, Add, Insert (¾), CCase
Menu 8ths, Add, Insert (⅞), CCase
Menu 8ths, Add
; ╞──────── 
Menu 5ths, Add
 Menu 5ths, Color, FFF8C7
Menu 5ths, Add, Insert (⅒), CCase
Menu 5ths, Add, Insert (⅕), CCase
Menu 5ths, Add, Insert (⅖), CCase
Menu 5ths, Add, Insert (⅗), CCase
Menu 5ths, Add, Insert (⅘), CCase
Menu 5ths, Add
; ╞──────── 
Menu 3rds, Add
 Menu 3rds, Color, FFF8C7
Menu 3rds, Add, Insert (↉), CCase
Menu 3rds, Add, Insert (⅑), CCase
Menu 3rds, Add, Insert (⅙), CCase
Menu 3rds, Add, Insert (⅓), CCase
Menu 3rds, Add, Insert (⅔), CCase
Menu 3rds, Add, Insert (⅚), CCase
Menu 3rds, Add
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Space, Add
Menu Space, Color, FFF8C7
Menu Space, Add, Insert Zero-Width ▏​▏, CCase
Menu Space, Add, Insert Hair-Width ▏ ▏, CCase
Menu Space, Add, Insert Six-Per-Em ▏ ▏, CCase
Menu Space, Add, Insert Thin-Width ▏ ▏, CCase
Menu Space, Add, Insert Punctuation ▏ ▏, CCase
Menu Space, Add, Insert Four-Per-Em ▏ ▏, CCase
Menu Space, Add, Insert Three-Per-Em ▏ ▏, CCase
Menu Space, Add, Insert Figure-Width ▏ ▏, CCase
Menu Space, Add, Insert En-Width ▏ ▏, CCase
Menu Space, Add, Insert Em-Width ▏ ▏, CCase
Menu Space, Add, Insert Braille-Blank ▏⠀▏, CCase
Menu Space, Add, Insert WhiteSpaceman ▏👨🏻‍🚀▏, CCase
Menu Space, Add
Menu Arrow Insert, Add, Arrows: , :Arrow
Menu Bullet Insert, Add, Bullets: , :Bullet
Menu Encloser Insert, Add, Enclosers: , :Encloser
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Fraction Insert, Add
Menu Fraction Insert, Add, Eighths: , :8ths
Menu Fraction Insert, Add
Menu Fraction Insert, Add, Thirds: , :3rds
Menu Fraction Insert, Add
Menu Fraction Insert, Add, Fifths: , :5ths
Menu Fraction Insert, Add
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Space Insert, Add, Spaces: , :Space
Menu Insert, Add, Arrows: , :Arrow Insert 	 ; ←←← ARROWS HEADER
Menu Insert, Add
Menu Insert, Add, Bullets: , :Bullet Insert 	 ; ←←← BULLETS HEADER
Menu Insert, Add
Menu Insert, Add, Enclosers: , :Encloser Insert 	 ; ←←← ENCLOSERS HEADER
Menu Insert, Add
Menu Insert, Add, Fractions: , :Fraction Insert 	 ; ←←← FRACTIONS HEADER.
Menu Insert, Add
Menu Insert, Add, Spaces: , :Space Insert 	 ; ←←← SPACES HEADER.
Menu Insert, Color, D1FFF0
Menu Case, Add, Inserts: , :Insert 		 ; ←←← INSERTS HEADER.
Menu Insert, Add
; ◦ ◦ ◦ ◦ ◦ ◦ ◦ 
Menu Case, Add 
Menu Case, Add, Toggle Dark Mode, CCase
; Menu Case, Add, • • • • • • • • • • • • ,  CCase 
Menu Case, Add 

; ▎░░░░░░░░░ HOTKEY ░░░░░░░░░▎ 
#If GetKeyState("Ctrl","P") 

*Y:: 	; ←←←←←← Trigger Key 
  Gosub, IndicateDot1
Gui, Color, LIME 
  Gosub, IndicateDot2
  KeyWait CapsLock,T.2 
  If !ErrorLevel{ 
    KeyWait CapsLock,D T.1 
    If !ErrorLevel { 
     sleep 100
    send ^a 
    sleep 200
    GetText(TempText)
    Menu Case, Show 
                            }
    Else { 
             GetText(TempText)
      Menu Case, Show 
             }
                            }
Return
#If 

; ╞═══════════ SWITCH CASES ═══════════╡ 

CCase: 
  Switch A_ThisMenuItem {

; ╞───────────── Main Cases ───────────────╡
; ╞─────── Press Number To Switch Case ───────╡

    Case "&1 UPPERCASE": 
      StringUpper, TempText, TempText

    Case "&2 lowercase": 
      StringLower, TempText, TempText

    Case "&3 Title Case": 
      StringLower, TempText, TempText, T

    Case "&4 Sentence case": 
      StringLower, TempText, TempText
      TempText := RegExReplace(TempText, "((?:^|[.!?]\s+)[a-z])", "$u1")

    Case "&5 iNVERT cASE": 
      {
         CopyClipboardCLM()
         Inv_Char_Out := ""
         Loop % StrLen(Clipboard)
         {
             Inv_Char := SubStr(Clipboard, A_Index, 1)
             if Inv_Char is Upper
                 Inv_Char_Out := Inv_Char_Out Chr(Asc(Inv_Char) + 32)
             else if Inv_Char is Lower
                 Inv_Char_Out := Inv_Char_Out Chr(Asc(Inv_Char) - 32)
             else
                 Inv_Char_Out := Inv_Char_Out Inv_Char
         }
         Clipboard := Inv_Char_Out
         PasteClipboardCLM()
      }

; ╞═══════════ Additionals ═══════════╡ 

    Case "Insert Date (MM/DD/YY)": 
        FormatTime, CurrentDateTime,,MM/dd/yy
        SendInput %CurrentDateTime%
    exit

    Case "Insert Degree Symbol (°)": 
        SendInput {Raw}°
    Return

; ╞───────────── Other Cases ──────────────╡

    Case "SpOnGeBoB cAsE": 
      {
          CopyClipboardCLM()
          Inv_Char_Out := ""
          StringLower, Clipboard, Clipboard
          Loop, Parse, Clipboard
          {
              if (Mod(A_Index, 2) = 0)
          Inv_Char_Out .= Format("{1:L}", A_LoopField)
              else
                  Inv_Char_Out .= Format("{1:U}", A_LoopField)                  
          }
          Clipboard := Inv_Char_Out
          PasteClipboardCLM()
      }

    Case "S p r e a d  T e x t  C a s e":
    {
    vText := "exemple"
    TempText := % RegExReplace(TempText, "(?<=.)(?=.)", " ")
    } 

    Case "raNDoM cASE":
    {
       CopyClipboardCLM()
       RandomCase := ""
      for _, v in StrSplit(Clipboard)
     {
         Random, r, 0, 1
         RandomCase .= Format("{:" (r?"L":"U") "}", v)
      }
      Clipboard := RandomCase
      PasteClipboardCLM()
    }

    Case "Reverse Case - esaC esreveR":
      Temp2 =
      StringReplace, TempText, TempText, `r`n, % Chr(29), All
      Loop Parse, TempText
        Temp2 := A_LoopField . Temp2
      StringReplace, TempText, Temp2, % Chr(29), `r`n, All 

; ╞═══════════ Inserts ═══════════╡ 

; ╞─────────────  Arrows ──────────────────╡ 

    Case "Insert Up Arrow (↑)": 
        SendInput {Raw}↑
    Return

    Case "Insert Down Arrow (↓)": 
        SendInput {Raw}↓
    Return

    Case "Insert Left Arrow (←)": 
        SendInput {Raw}←
    Return

    Case "Insert Right Arrow (→)": 
        SendInput {Raw}→
    Return

    Case "Insert Horizontal Arrow (↔)": 
        SendInput {Raw}↔
    Return

    Case "Insert Verticle Arrow (↕)": 
        SendInput {Raw}↕
    Return

    Case "Insert UpLeft Arrow (↖)": 
        SendInput {Raw}↖
    Return

    Case "Insert UpRight Arrow (↗)": 
        SendInput {Raw}↗
    Return

    Case "Insert DownLeft Arrow (↙)": 
        SendInput {Raw}↙
    Return

    Case "Insert DownRight Arrow (↘)": 
        SendInput {Raw}↘
    Return

; ╞─────────────  Bullets ──────────────────╡ 5

    Case "Insert Big Dot Bullet (●)": 
        SendInput {Raw}●
    Return

    Case "Insert Small Dot Bullet (•)": 
        SendInput {Raw}•
    Return

    Case "Insert Big Square Bullet (■), CCase": 
        SendInput {Raw}■
    Return

    Case "Insert Small Square Bullet (▪)": 
        SendInput {Raw}▪
    Return

    Case "Insert Big Empty Square Bullet (☐)": 
        SendInput {Raw}☐
    Return

    Case "Insert Small Empty Square Bullet (▫)": 
        SendInput {Raw}▫
    Return

    Case "Insert Big EmptyDot Bullet (○)": 
        SendInput {Raw}○
    Return

    Case "Insert Small Empty Dot Bullet (◦)": 
        SendInput {Raw}◦
    Return

    Case "Insert Black Diamond Bullet (◆)": 
        SendInput {Raw}◆
    Return

    Case "Insert Empty Diamond  Bullet (◇)": 
        SendInput {Raw}◇
    Return

    Case "Insert Centered Diamond Bullet (◈)": 
        SendInput {Raw}◈
    Return

    Case "Insert Black Diamond Star Bullet (✦)": 
        SendInput {Raw}✦
    Return

    Case "Insert Empty Diamond Star Bullet (✧)": 
        SendInput {Raw}✧
    Return

; ╞───────────── Enclosers ─────────────────╡ 2

    Case "″…″ Quotes": 
      TempText := RegExReplace(TempText, "\s+$") 
      TempText := """" TempText """"

    Case "'…' Apostrophes": 
        TempText := RegExReplace(TempText, "\s+$") 
    TempText := "'" TempText "'"

    Case "(…) Parentheses": 
      TempText := RegExReplace(TempText, "\s+$") 
      TempText := "(" TempText ")"

    Case "`{…} Curly Brackets": 
      TempText := RegExReplace(TempText, "\s+$") 
      TempText := "{" TempText "}"

    Case "`[…] Square Brackets": 
      TempText := RegExReplace(TempText, "\s+$") 
      TempText := "[" TempText "]"

    Case "`*…* Asterisks": 
      TempText := RegExReplace(TempText, "\s+$") 
      TempText := "*" TempText "*"

; ╞───────────── Fractions ─────────────────╡ 3.5

    Case "Insert (⅛)": 
        SendInput {Raw}⅛
    Return

    Case "Insert (¼)": 
        SendInput {Raw}¼
    Return

    Case "Insert (⅜)": 
        SendInput {Raw}⅜
    Return

    Case "Insert (½)": 
        SendInput {Raw}½
    Return

    Case "Insert (⅝)": 
        SendInput {Raw}⅝
    Return

    Case "Insert (¾)": 
        SendInput {Raw}¾
    Return

    Case "Insert (⅞)": 
        SendInput {Raw}⅞
    Return

    Case "Insert (↉)": 
        SendInput {Raw}↉
    Return

    Case "Insert (⅑)": 
        SendInput {Raw}⅑
    Return

    Case "Insert (⅙)": 
        SendInput {Raw}⅙
    Return

    Case "Insert (⅓)": 
        SendInput {Raw}⅓
    Return

    Case "Insert (⅔)": 
        SendInput {Raw}⅔
    Return

    Case "Insert (⅚)": 
        SendInput {Raw}⅚
    Return

    Case "Insert (⅒)": 
        SendInput {Raw}⅒
    Return

    Case "Insert (⅕)": 
        SendInput {Raw}⅕
    Return

    Case "Insert (⅖)": 
        SendInput {Raw}⅖
    Return

    Case "Insert (⅗)": 
        SendInput {Raw}⅗
    Return

    Case "Insert (⅘)": 
        SendInput {Raw}⅘
    Return

; ╞─────────────  Spaces ──────────────────╡ 6

    Case "Insert Zero-Width ▏​▏": 
        SendInput {Raw}​
    Return

    Case "Insert Hair-Width ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "Insert Six-Per-Em ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "Insert Thin-Width ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "Insert Punctuation ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "Insert Four-Per-Em ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "Insert Three-Per-Em ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "nsert Figure-Width ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "Insert En-Width ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "Insert Em-Width ▏ ▏": 
        SendInput {Raw} 
    Return

    Case "Insert Braille-Blank ▏⠀▏": 
        SendInput {Raw}⠀
    Return

    Case "Insert WhiteSpaceman ▏👨🏻‍🚀▏": 
        SendInput {Raw}👨🏻‍🚀
    Return 

; ╞───────────────────────────────────────╡

; ╞═══════════ Dark Mode ═══════════╡ 

    Case "Toggle Dark Mode":
      If (DarkMode)
    {
      DarkMode := false
          MenuDark(3) ; Set to ForceLight
      WelcomeTrayTipLight()
    }
    else
    {
      DarkMode := true
          MenuDark(2) ; Set to ForceDark
    WelcomeTrayTipDark()
    }
Return
   }
SetCapsLockState, Off

; ╞───────────────────────────────────────╡

/*
; ▎░░░░░░░ Reload Lines ? ░░░░░░░░░░▎ 

    Case "• • • • • • • • • • • •": 
;      Soundbeep, 2000, 100
      Reload

    Case "• • • • • • • • • • • • ": 
;      Soundbeep, 2000, 100
      Reload

; ▎░░░░░░░░░░░░░░░░░░░░░░░░░▎ 
*/

; ╞═══════════ This has to be at BOTTOM OF ALL THE CASE THINGS (Pastes TempText) ═══════════╡ 
 
PutText(TempText)
    SetCapsLockState, Off
Return

; ╞──────── BOTTOM OF ALL THE CASE THINGS End ────────╡ 

; ╞═══════════ Functions ═══════════╡ 

GetText(ByRef MyText = "")
{
   SavedClip := ClipboardAll
   Clipboard =
   Send ^c
   ClipWait 0.5
   If ERRORLEVEL
   {
      Clipboard := SavedClip
      MyText =
      Return
   }
   MyText := Clipboard
   Clipboard := SavedClip
   Return MyText
}
 
PutText(MyText) 
{
   SavedClip := ClipboardAll
   Clipboard =
   Sleep 20
   Clipboard := MyText
   Send ^v
   Sleep 100
   Clipboard := SavedClip
   Return
}

CopyClipboard()
{
    global ClipSaved := ""
    ClipSaved := ClipboardAll
    Clipboard := ""
    Send {Ctrl down}c{Ctrl up}
    Sleep 150
    ClipWait, 1.5, 1
    if ErrorLevel
    {
        MsgBox, 262208, AutoHotkey, Copy to clipboard failed!
        Clipboard := ClipSaved
        ClipSaved := ""
        Return
    }
}

CopyClipboardCLM()
{
    global ClipSaved
    WinGet, id, ID, A
    WinGetClass, class, ahk_id %id%
    if (class ~= "(Cabinet|Explore)WClass|Progman")
        Send {F2}
    Sleep 100
    CopyClipboard()
    if (ClipSaved != "")
        Clipboard := Clipboard
    else
        Exit
}

PasteClipboardCLM()
{
    global ClipSaved
    WinGet, id, ID, A
    WinGetClass, class, ahk_id %id%
    if (class ~= "(Cabinet|Explore)WClass|Progman")
        Send {F2}
    Send ^v
    Sleep 100
    Clipboard := ClipSaved
    ClipSaved := ""
    Exit
}
 
SetCapsLockState, Off
Send, {capslock up}

; ╞═══════════ Dark Mode ═══════════╡ 

DarkMode := false

MenuDark()

MenuDark(Dark := 2) {  ; 0=Default  1=AllowDark  2=ForceDark  3=ForceLight  4=Max
    static uxtheme := DllCall("GetModuleHandle", "str", "uxtheme", "ptr")
    static SetPreferredAppMode := DllCall("GetProcAddress", "ptr", uxtheme, "ptr", 135, "ptr")
    static FlushMenuThemes := DllCall("GetProcAddress", "ptr", uxtheme, "ptr", 136, "ptr")
     DllCall(SetPreferredAppMode, "int", Dark) 
    DllCall(FlushMenuThemes)
}

; ╞──────── Dark Mode End ────────╡ 

; ╞═══════════ Dark/Light Mode Activated Gui ═══════════╡ 

WelcomeTrayTipDark() {
    static GuiCreated := 0
    static HwndWelcomeScreen1
    static MonRight, MonBottom
    if !GuiCreated  {
        GuiCreated := 1
        Gui, WelcomeScreen1:New, 
            +AlwaysOnTop 
            -Caption 
            +ToolWindow 
            +HwndHwndWelcomeScreen1 
            +LastFound 
            -DPIScale 
            +E0x20 ; Clickthrough=E0x20
        Gui, WelcomeScreen1:Margin, 10, 20
        Gui, WelcomeScreen1:Font, s14 w600 q5, Segoe UI
        Gui, WelcomeScreen1:Color, BLACK 
        Gui, WelcomeScreen1:Add, Text, y20 c46BCFF, Dark Mode Activated
        WinSet, Transparent, 0
        SysGet, P, MonitorPrimary
        SysGet, Mon, MonitorWorkArea, % P
        Gui, WelcomeScreen1:Show, Hide
        WinGetPos, X, Y, W, H
        WinMove, % MonRight - W - 10, % MonBottom - H - 10
        WinSet, Region, 0-0 W%W% H%H% R20-20
    }
    Gui, WelcomeScreen1:Show, NA
    bf := Func("AnimateFadeIn").Bind(HwndWelcomeScreen1)
    SetTimer, %bf%, -200
}
; ◦ SWITCH ◦ 
WelcomeTrayTipLight() {
    static GuiCreated := 0
    static HwndWelcomeScreen
    static MonRight, MonBottom
    if !GuiCreated  {
        GuiCreated := 1
        Gui, WelcomeScreen:New, 
            +AlwaysOnTop 
            -Caption 
            +ToolWindow 
            +HwndHwndWelcomeScreen 
            +LastFound 
            -DPIScale 
            +E0x20 ; Clickthrough=E0x20
        Gui, WelcomeScreen:Margin, 10, 20
        Gui, WelcomeScreen:Font, s14 w600 q5, Segoe UI
        Gui, WelcomeScreen:Color, WHITE 
        Gui, WelcomeScreen:Add, Text, y20 c1AFF1A, Light Mode Activated
        WinSet, Transparent, 0
        SysGet, P, MonitorPrimary
        SysGet, Mon, MonitorWorkArea, % P
        Gui, WelcomeScreen:Show, Hide
        WinGetPos, X, Y, W, H
        WinMove, % MonRight - W - 10, % MonBottom - H - 10
        WinSet, Region, 0-0 W%W% H%H% R20-20
    }
    Gui, WelcomeScreen:Show, NA
    bf := Func("AnimateFadeIn").Bind(HwndWelcomeScreen)
    SetTimer, %bf%, -200
}

; ╞──────── Dark/Light Mode Activated Gui End ────────╡ 

; ╞═══════════ Gui FadeIn-Out Function ═══════════╡ 

AnimateFadeIn(hwnd) {
    static Value := 0
    WinSet, Transparent, % Value+=15, % "ahk_id" hwnd
    if (Value >= 255) {
        Value := 0
        bf := Func("AnimateFadeOut").Bind(hwnd)
        SetTimer, %bf%, -1000
    } else {
        bf := Func("AnimateFadeIn").Bind(hwnd)
        SetTimer, %bf%, -15
    }
}
; ◦ SWITCH ◦ 
AnimateFadeOut(hwnd) {
    static Value := 255
    WinSet, Transparent, % Value-=15, % "ahk_id" hwnd
    if (Value <= 0) {
        Value := 255
        Gui, %hwnd%:Hide
    } else {
        bf := Func("AnimateFadeOut").Bind(hwnd)
        SetTimer, %bf%, -15
    }
}

; ╞──────── Gui FadeIn-Out Function End ────────╡ 

; ╞═══════════ Reload/Exit Routine ═══════════╡ 
RETURN

; ◦ ◦ ◦ ◦ ◦ ◦ ◦ RELOAD  SCRIPT ◦ ◦ ◦ ◦ ◦ ◦ ◦ 

^Home:: 		  ; (Ctrl + ([Home] times (# of TapCounts)))
if (A_TimeSincePriorHotkey > 250) 
{
    TapCount := 1
    KeyWait, Esc
} else {
    TapCount++
    if (TapCount = 2) 	 ; ←←← Set TapCount to # of key taps wanted.
    {
  Gosub, IndicateDot1
Gui, Color, YELLOW 		 ; ←←← IndicateDot Color.
  Gosub, IndicateDot2
        Reload
} else {
        KeyWait, Esc
    }
}
Return

; ◦ ◦ ◦ ◦ ◦ ◦ ◦ EXIT SCRIPT ◦ ◦ ◦ ◦ ◦ ◦ ◦ 

^Esc:: 		; (Ctrl + ([Esc] times (# of TapCounts)))
if (A_TimeSincePriorHotkey > 250) 
{
    TapCount := 1
    KeyWait, Esc
} else {
    TapCount++
    if (TapCount = 3) 	 ; ←←← Set TapCount to # of key taps wanted.
    {
  Gosub, IndicateDot1
Gui, Color, RED 		 ; ←←← IndicateDot Color.
  Gosub, IndicateDot2
        Gui, Destroy
        ExitApp
} else {
        KeyWait, Esc
    }
}
Return

; ╞──────── Reload/Exit Routine End ────────╡ 

; ╞═══════════ Script Updater ═══════════╡ 
UpdateCheck: 				 ; Check if the script file has been modified.
    oldModTime := currentModTime
FileGetTime, currentModTime, %A_ScriptFullPath%
; ◦ ◦ ◦ ◦ ◦ ◦ If the modification timestamp has changed, reload the script.
    if  (oldModTime = currentModTime) Or (oldModTime = "")
        Return
  Gosub, IndicateDot1
Gui, Color, BLUE 		 ; ←←← IndicateDot Color.
  Gosub, IndicateDot2
Reload

; ╞──────── Script Updater End ────────╡ 

; ╞═══════════ Auto-Execute Sub ═══════════╡ 
AutoExecute: 
#NoEnv
#SingleInstance, Force
#Persistent
DetectHiddenWindows, On
SendMode Input ; Makes Send synonymous with SendInput.
SetBatchLines -1 ; Determines how fast a script will run.
SetKeyDelay, 250 ; Sets TapCount allowed delay time (milliseconds) for script Exit. (tied to Reload/Exit routine)
SetTimer, UpdateCheck, 500 ; Checks for script changes every 1/2 second. (Script Updater)
SetTitleMatchMode 2 ; Sets the matching behavior of the WinTitle parameter.
SetWorkingDir %A_ScriptDir% ; Scripts own directory. (, FileSelectFolder) - allows user to select a folder.
Menu, Tray, Icon, wmploc.dll, 99 ; Local White Star tray Icon.

; ╞──────── Auto-Execute Sub End ────────╡ 

; ╞═══════════ GoSubs ═══════════╡ 
IndicateDot1:
Gui, Destroy
SysGet, MonitorWorkArea, MonitorWorkArea
SysGet, TaskbarPos, 4
Gui, +AlwaysOnTop -Caption +hwndHGUI +LastFound
Return

; ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ ◦ 

IndicateDot2:
Gui, Margin, 13, 13 	 ; ←←← Dot Size.
Gui, Show, Hide
WinGetPos, , , WinWidth, WinHeight, ahk_id %HGUI%
NewX := MonitorWorkAreaRight - 80
NewY := MonitorWorkAreaBottom - WinHeight - 5
R := Min(WinWidth, WinHeight) // 1 	 ; ←←← Set value of cornering. (0.5=Oval, 0=square, 1= round, 5=rounded corners).
WinSet, Region, 0-0 W%WinWidth% H%WinHeight% R%R%-%R%
Gui, Show, x%NewX% y%NewY%
SoundGet, master_volume
SoundSet, 2
Soundbeep, 2100, 150
SoundSet, % master_volume
Sleep, 500
Gui, Destroy
Return

; ╞──────── GoSubs End ────────╡ 

; ╞──────────────────────────╡ 
; ╞═══════════ Script End ═══════════╡ 
; ╞──────────────────────────╡ 
  light and dark mode
image.png
image.png (41.15 KiB) Viewed 1046 times
Last edited by V0RT3X on 20 Jun 2023, 08:51, edited 2 times in total.
User avatar
Kellyzkorner_NJ
Posts: 84
Joined: 20 Oct 2017, 18:33

Re: Menu with a sub-submenu?

19 Jun 2023, 20:43

@kunkel321

I think this might be it:

viewtopic.php?t=45649 by maestrith. Thanks for posting it, it's awesome!

Kelly
User avatar
kunkel321
Posts: 1194
Joined: 30 Nov 2015, 21:19

Re: Menu with a sub-submenu?

20 Jun 2023, 08:14

Kellyzkorner_NJ wrote:
19 Jun 2023, 20:43
@kunkel321
I think this might be it:
viewtopic.php?t=45649 by maestrith. Thanks for posting it, it's awesome!
Kelly
That's the one! Thanks Kelly!
I've updated the above post.
ste(phen|ve) kunkel

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Marium0505, mcl and 340 guests