Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[module] MMenu 1.0 b1


  • Please log in to reply
126 replies to this topic
majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I seek for help if anybody cares:

This is pIcon from the Add function

pIcon Optional path to the icon for the item; if you set the number, it will be seen as the icon handle. You can use 32x32 icons from resources if you specify :idx after icon path ( shell32.dll:4 )


I am seraching a method to extract icons of different size. Currently I am using this function:

MSDN
MMenu_getIcon( pPath, pNum=1 ) {
	return, DllCall("Shell32\ExtractIconA", "UInt", 0, "Str", pPath, "UInt", pNum)
}
It seems that this one can extract only large or small icons as defined by the system.

I think that LoadImage API can do it, but didn't manage to use it.

Can anybody help?

THis is in order to be able to extract icons of adequate size for executables. For instance, if you set MMenu icon size to be 24 and you specify icon from the resource it will be 32 and so cutted off.


The related topic on Ask for Help is:
<!-- m -->http://www.autohotke... ... loadimage<!-- m -->
Posted Image

kiu
  • Members
  • 234 posts
  • Last active: Oct 10 2010 07:30 PM
  • Joined: 18 Dec 2005
What about loading the icon as 32x32 and then modify its size using Image conversions and capturing with GDI+?
Maybe it's possible to do it in this way :?:
Anyway as I have a little more time I'll try to search how to do it with PhiLho's API
____________________
______________________
kiu - www.romeosa.com

kiu
  • Members
  • 234 posts
  • Last active: Oct 10 2010 07:30 PM
  • Joined: 18 Dec 2005
I suggested it cause I'm trying to find a way to show menu icons also from image files, but I'm relatively new to DllCall, so...
____________________
______________________
kiu - www.romeosa.com

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
well.... that is not the good way. Icon will be very distorted. If there are other sizes its best to use them.
Posted Image

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
Hi majkinetor,

I tried your MMenu on a small example for test purposes. I want the menu to show me the number of folders and files in two directories. But since that process takes some time I wanted the user to see the counting with alive update of the menu. But it doesn't seem to work. What am I doing wrong here?
Sometimes the menu doesn't react or is only have displayed.

Could you please advice a solution?

#SingleInstance force
#NoEnv
#include includes
#include MMenu.ahk
#include structs.ahk

CoordMode, tooltip, screen

	main := MMenu_Create()
	prog := MMenu_Create()
	docs := MMenu_Create()

	MMenu_Add( main, "Move on a item","", "", "d iDoNothing")
	MMenu_Add( main, "Programs", "", "", "m" prog)
	MMenu_Add( main, "Documents", "", "", "m" docs )

  MMenu_Add(prog, "Please wait!",  "", "", "d iDoNothing")
  MMenu_Add(prog, "Path",          "", "", "iDoNothing")
  MMenu_Add(prog, "# of folders",  "", "", "iDoNothing")
  MMenu_Add(prog, "# of files",    "", "", "iDoNothing")
  MMenu_Add(prog, "Last modified", "", "", "iDoNothing")
  MMenu_Add(prog, "Sum file size", "", "", "iDoNothing")

  MMenu_Add(prog, "Result", "", "", "b| d iDoNothing")
  MMenu_Add(prog, "x",      "", "", "iPPath")
  MMenu_Add(prog, "x",      "", "", "iPFolder")
  MMenu_Add(prog, "x",      "", "", "iPFiles")
  MMenu_Add(prog, "x",      "", "", "iPLastMod")
  MMenu_Add(prog, "x",      "", "", "iPSize")

  MMenu_Add(docs, "Please wait!",  "", "", "d iDoNothing")
  MMenu_Add(docs, "Path",          "", "", "iDoNothing")
  MMenu_Add(docs, "# of folders",  "", "", "iDoNothing")
  MMenu_Add(docs, "# of files",    "", "", "iDoNothing")
  MMenu_Add(docs, "Last modified", "", "", "iDoNothing")
  MMenu_Add(docs, "Sum file size", "", "", "iDoNothing")

  MMenu_Add(docs, "Result", "", "", "b| d iDoNothing")
  MMenu_Add(docs, "x",      "", "", "iDPath")
  MMenu_Add(docs, "x",      "", "", "iDFolder")
  MMenu_Add(docs, "x",      "", "", "iDFiles")
  MMenu_Add(docs, "x",      "", "", "iDLastMod")
  MMenu_Add(docs, "x",      "", "", "iDSize")


	MMenu_Show( main, A_SCreenWidth/2-100, A_ScreenHeight/2-100, "OnMMenu", "IOnInit UOnUninit" )
	ExitApp
return

OnMMenu:
return

OnUninit:
	StopToGatherData := True
  MMenu_Set(prog, "PPath", "x")
  MMenu_Set(prog, "PFolder", "x")
  MMenu_Set(prog, "PFiles", "x")
  MMenu_Set(prog, "PLastMod", "x")
  MMenu_Set(prog, "PSize", "x")
  MMenu_Set(docs, "DPath", "x")
  MMenu_Set(docs, "DFolder", "x")
  MMenu_Set(docs, "DFiles", "x")
  MMenu_Set(docs, "DLastMod", "x")
  MMenu_Set(docs, "DSize", "x")
return

OnInit:
  If (M_Menu = Prog){
      StopToGatherData := False
      SetTimer, StartProg, 10
  }Else If (M_Menu = Docs){
      StopToGatherData := False
      SetTimer, StartDocs, 10
    }
Return

StartProg:
  SetBatchLines, 50ms
  SetTimer, StartProg, Off
  StartToGatherData("P", A_ProgramFiles)
Return

StartDocs:
  SetBatchLines, 50ms
  SetTimer, StartDocs, Off
  StartToGatherData("D", A_MyDocuments)
Return
    
StartToGatherData(Type, Path){
    global StopToGatherData,prog,docs

    Time := A_TickCount
    ToolTip, Timer Start

    GetDirDate(Type, Path, NumDirs := 0, NumFiles := 0, LastModTime := 10000000000000, Size := 0)
    If StopToGatherData
        Return
        
    menu := Type = "P" ? "prog" : "docs"
    MMenu_Set(%menu%, Type "Path",    Path)
    MMenu_Set(%menu%, Type "Folder",  NumDirs)
    MMenu_Set(%menu%, Type "Files",   NumFiles)
    MMenu_Set(%menu%, Type "LastMod", LastModTime)
    MMenu_Set(%menu%, Type "Size",    Size)
    
    Time := A_TickCount - Time
    Tooltip, Timer Stop %Time% ms
  }

GetDirDate(Type, ByRef Path, ByRef NumDirs, ByRef NumFiles, ByRef LastModTime, ByRef Size){
    global StopToGatherData,prog,docs

    SetBatchLines, 100ms

    menu := Type = "P" ? "prog" : "docs"
    MMenu_Set(%menu%, Type "Path", Path)

    Loop, %Path%\*, 1, 1
      {
        If A_LoopFileAttrib contains D
          {
            NumDirs++
            If !Mod(NumDirs, 20)
                MMenu_Set(%menu%, Type "Folder", NumDirs)
        }Else{
            NumFiles++
            Size += A_LoopFileSize    ;in bytes
            If !Mod(NumFiles, 100)
                MMenu_Set(%menu%, Type "Files", NumFiles)
          }
        LastModTime := LastModTime > A_LoopFileTimeModified ? LastModTime : A_LoopFileTimeModified
        If StopToGatherData
            Return
      }
    FormatTime, LastModTime, %LastModTime%, ShortDate
    If (Size > 1024 * 1024 * 1024)
        Size := Round(Size / (1024 * 1024 * 1024),3) . " Gb"
    Else If (Size > 1024 * 1024)
        Size := Round(Size / (1024 * 1024),3) . " Mb"
    Else If (Size > 1024)
        Size := Round(Size / 1024, 3) . " Kb"
    Else If Size = 0
        Size .= "empty"
    Else If Size = 1
        Size .= " byte"
    Else
        Size .= " bytes"
  }

Edit: Fixed a small bug
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
I was doing something similar and will post it soon.
FolderMenu that I created load arbitrary folder into the menu. If you call menu while it is in building process you can see first item of the menu being the word "---- IN PROGRESS ---- ". It continues to build menu in the background though, so next time you call it, it will show full menu, or again "in progress" with more items.

I think that dynamic adding of menu items can not be done now with real time update, but I really don't know for sure, as i didn't experiment much with this, it seemd like not important. You can change existing items which is demonstrated with time in the test example. One possible quick solution would be to first add all items as separators, like, if you have 100 files in the folder, you add 100 separators. Then you iterate trought menu using ID's and remove "s" option, change the name to the name of the file, change the icon to the icon of the file. Be aware that this introduces some small bug that happens when you first define all items in the menu without icons, then add icons (some trailin title letters will be cut of). For that, you must add at least 1 icon at the beginning. You can add icon to the separator to fix this, put the same handle for all separator icons. The point to note here that separator in MMenu is dynamic, you can turn any item into separator and vice-versa.

I will post here FolderMenu when I update it to use newest MMenu API as I did it after first API version was completed and didn't find time to update it yet. You can use it to show/create menu like this:

FolderMenu("c:\program files", options="")

Options are there for some things, like wether to include system and hidden files, wether to break the menu after some number of files, if to load icons etc...

If you want to stick with your code, I can check it out latter and see what I can do about it.
Posted Image

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
It seems when there is a timer running (even with SetBatchLines, 100ms) a while longer the menu isn't responding. I tried to start the timer oustide the OnInit function and the same happend.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Using timers with MMenu isn't good idea, I must documente that. I use it only to postpone execution some number of milliseconds, like for Tooltip example.

Always runnig timer will interfere with MMenu handlers. This is actually hack of AHK, provided to me by Chris. You know that script is blocked when AHK menu is shown, and it continues after user closes the menu. In MMenu, it is not blocked but I let the script go using some info Chris told me, so you are able to process handlers. Keep in mind that although MMenu is very entusiasticaly desgined there are still lot of AHK limitations that forbid it to do some things like a charm. This kind of thing can be 100% successifully done only natively, using C. You shouldn't put MMenu in very stresfull situations, like doing bunch of things in the background while it is displayed, using timers, etc.... The other things that prevents to create and delete menus all the time without losing performance will be fixed in next update.
Posted Image

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
From your reply I see that you didn't look at my code. Not a problem.

I thought as well that it might be problematic to add item dynamically. That's why I added them with a "x" and gave them names. And during the counting I change the text of the items. But why isn't this working. It works in GUIs. Is there someting in the code that prevents these updates?

Edit: I didn't use the timer constantly. I only use it to create a new thread.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006

From your reply I see that you didn't look at my code. Not a problem.


If you want to stick with your code, I can check it out latter and see what I can do about it.


I am very tired now, can't look at any code, I had exame yesterday from 8 - 23, I barely work today, mainly surf around...

But why isn't this working. It works in GUIs.

I will let you know when I check it out.
Posted Image

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
Thanks a lot. Much appreciated. Have fun surfing. I hope your exames were successful.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
well, it works here :)

I see number of files counting :)

Documents executes in 1 sec and I can barely see it counting, but Program Files executes for minutes and I see counting all the time. The only problematic thing here is that you can't exit Program Files menu while it is counting or use it at all but I guess Thread, NoTimers somewhere in the MMenu code may fix that.

Thanks a lot. Much appreciated. Have fun surfing. I hope your exames were successful.

They were. It was pretty intensive law shit as I work in ministry institution. Failure was punishable by getting fired.


EDIT:

It has nothing to do with timers. You blocked the script as loop doesn't permit windows messages to run. The same would happen in C code, even worst, gui wouldn't be udpated at all, you are lucky AHK does that on its own from time to time. Even the sleep -1 didn't help at the beginning of the loop. I will see if I can do something for such cases.

Other then that, your menu looks really kewl. I will see what I can do so this beauty works. I think that this is some AHK limitation and that this must be designed differently to workaround that, but I will see more.

I really don't know what blocks the menu. I tried this

GetDirDate(Type, ByRef Path, ByRef NumDirs, ByRef NumFiles, ByRef LastModTime, ByRef Size){
    global StopToGatherData,prog,docs
	[color=blue]Thread, Priority, -2147483648[/color]

then this

Loop, %Path%\*, 1, 1
      {
		sleep, -1 ; sleep 100, 1000

Posted Image

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Ok, this is rather inventive way, and it seems it doesn't block the menu
DummyTimer:
     StartToGatherData("P", A_ProgramFiles, [color=blue]CONTINUE[/color])
return

GetDirDate(Type, ByRef Path, ByRef NumDirs, ByRef NumFiles, ByRef LastModTime, ByRef Size){
    global StopToGatherData,prog,docs

    menu := Type = "P" ? "prog" : "docs"
    MMenu_Set(%menu%, Type "Path", Path)

    Loop, %Path%\*, 1, 1
      {
		
		[color=blue]if !Mod(A_Index, 50)
		{
			SetTimer, DummyTimer, 50
			return
		}[/color]

The point is to let the loop break at certain number of files to give the script a rest for GUI to update. The Dummy timer should continue the iteration where Mod() exited.

I did put here just call to original function again, from the beginning to see if it works.

I am still confused why sleep, -1 doesn't work, which is the same as ProcessMessages or DoEvents in Delphi, that is dotNet. Or priority.

Maybe Chris can enligthen us

EDIT: This also means that u can't use Loop, but some other form of iteration that allows to be continued, like APIs GetNextFile, GetFirstFile.

Its funny that the sleep -1 mechanism works in "modality scenario"

Gui, show....

loop
{
   sleep, -1 ; or sleep 200
   if !gui_visible
      break
}

Posted Image

toralf
  • Moderators
  • 4035 posts
  • Last active: Aug 20 2014 04:23 PM
  • Joined: 31 Jan 2005
Thanks for the help,

I managed to do it with the extra timer (break loop and start form that position again. Not very nice or effective, but the menu is responding again. If you find a better solution, please let me know.
Ciao
toralf
 
I use the latest AHK version (1.1.15+)
Please ask questions in forum on ahkscript.org. Why?
For online reference please use these Docs.

majkinetor
  • Moderators
  • 4512 posts
  • Last active: May 20 2019 07:41 AM
  • Joined: 24 May 2006
Good, I am glad.

I hope you are aware its not MMenu problem at all. What you did is typical mistake which is not trivial to fix. Real solution is about splitting GUI and working procedure into 2 threads, and to call working procedure ASYNCRHONIOSLY. The message queue is in non working thread and GUI can respond normaly to messages while procedure is looping something. Procedure after that informs mother thread that it is finished via callbacks. This is not trivial even in dotNet which has very nice thread support. I know lot about this as I had this problem number of times.

As you see, this must be handled by specific design of scripts in AHK, as it doesn't support multithreading ( :( .... ) (callbacks are not so mandatory). I will try to see why sleep in loop doesn't work, as it would make ideal solution.
Posted Image