AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

MakeICOBars - Create icon bar graphs for tray & pic
Goto page Previous  1, 2, 3, 4  Next
 
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Wed Nov 28, 2007 9:26 pm    Post subject: Reply with quote

majkinetor wrote:
Use #NoTrayIcon as the first line in your script.
Then I'd have to change NIM_MODIFY to NIM_ADD and probably add a couple other fields... Razz
Quote:
Yes nice work lex. How have you created a header for the icon? and couldnt gdi+ be used for the transparency part?
No header. I create a 32-bit bitmap, draw onto it, then create an icon from the bitmap. GDI+ could be used, yes, but that's IMO not as easy to use. Manually setting the pixels works well and doesn't add a dependency on GDI+.

It occurred to me after I finished that I'd already written some code for dynamic icon generation. Mad It hadn't occurred to me since I used the icons in a ListView instead of the tray...
Back to top
View user's profile Send private message Visit poster's website
majkinetor



Joined: 24 May 2006
Posts: 4511
Location: Belgrade

PostPosted: Wed Nov 28, 2007 10:05 pm    Post subject: Reply with quote

Quote:
Then I'd have to change NIM_MODIFY to NIM_ADD and probably add a couple other fields...

It will solve the problem, right ? Razz
_________________
Back to top
View user's profile Send private message
majkinetor



Joined: 24 May 2006
Posts: 4511
Location: Belgrade

PostPosted: Thu Nov 29, 2007 8:45 am    Post subject: Reply with quote

I was playing with lexikos code and its really blazingly fast, like lex said.
My TaskInfo keeps long avarage CPU at 0 with loop that has 25ms sleep in it (you don't need faster then that). So, this is exactly the speed we want. Smile

Tic, you should use this method as basis for your final code. First of all, it totaly avoids machine code; not that i have something totaly against it, but going that deep generaly defits the reason we are here and I think about it only when there are not other options available in AHK. It will also make script updatable by only few people.

I also want to ask you to add additional parameter to the function, optional flag. When set to true, return icon handle, when set to false (default) do the same as now (save icon to hd).

Quote:
I would also really like to know which signs people think would be good as prefixs!

I have better proposal, IMO:
Code:
> overwrite right
< overwrite left
+ add right, shift contest left
- add left, shift contest right


Note that special chars for deleting are not necessary as you can get it with <0 and >0. Also, using single char will make your check very easy by using (*&input = asc) syntax.

To get the curve, we can first intialise icon with 32 zeros then use +NextVal to draw afterwards.
_________________
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Thu Nov 29, 2007 11:29 am    Post subject: Reply with quote

majkinetor wrote:
It will solve the problem, right ? Razz
Yes, and I would do it if I were intending to actually use the script. Laughing
majkinetor wrote:
My TaskInfo keeps long avarage CPU at 0 with loop that has 25ms sleep in it
I tried it with a Sleep of 1ms, and CPU stays mostly at 0% (instead of ~30%). It isn't even perceptibly slower!
Back to top
View user's profile Send private message Visit poster's website
majkinetor



Joined: 24 May 2006
Posts: 4511
Location: Belgrade

PostPosted: Thu Nov 29, 2007 11:39 am    Post subject: Reply with quote

Quote:
I tried it with a Sleep of 1ms, and CPU stays mostly at 0%

Yes, the same behavior here.

I wonder if such speed can be acomplished with same algorythm in AutoIt or VBscript.
_________________
Back to top
View user's profile Send private message
tic



Joined: 22 Apr 2007
Posts: 1786

PostPosted: Thu Nov 29, 2007 4:55 pm    Post subject: Reply with quote

I have posted the updated code in the 1st post, and modifiers are <,>,-,+
Also you shouldnt really need a sleep with this function now when looping it. I could get the speed down to a similar speed with the Shell notify, but I would have to remove all the features. It is comparitively fast now.

Remember when using - and + that they can only be used a maximum of 31 times in a row, as only 32 bars are allowed. To make the pixel 16 wide, only specify 16 points.

You may see in the example I am having some problems with Guicontrolling pictures. They flicker too much. Is there any way round this?
Back to top
View user's profile Send private message
Laszlo



Joined: 14 Feb 2005
Posts: 4710
Location: Boulder, CO

PostPosted: Thu Nov 29, 2007 5:22 pm    Post subject: Reply with quote

majkinetor wrote:
...avoids machine code; not that i have something totally against it, but going that deep generally defeats the reason we are here and I think about it only when there are not other options available in AHK. It will also make script updatable by only few people.
It is like a built in language feature: a simple task is made a standalone tool, short, lightning fast and only include it, when needed. You should never need to update a machine code function. Convert binary to hex or back is not what you modify, but use, like a standard function. The Windows libraries are much riskier: MS changes functions, they are different in different Windows versions. Your code works with the machine code function everywhere (assuming standard X86 instructions), but it may not work in certain Windows versions (95,98,ME) or setups (older .net libraries). In general, short machine code functions are safer, but of course, less powerful than Windows libraries.
Back to top
View user's profile Send private message
tic



Joined: 22 Apr 2007
Posts: 1786

PostPosted: Thu Nov 29, 2007 5:47 pm    Post subject: Reply with quote

I agree Laszlo and think that if people try out the bin2hex machine code included, then it aptly shows the advantage of using machine code. it shouldnt ever need to be updated and is very fast. its only used for writing the ico, so shouldnt need to be changed.

I would really love to know a way to change a pciture without it flickering as some really cool controls could be made with these icos.
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Thu Nov 29, 2007 7:50 pm    Post subject: Reply with quote

tic wrote:
I would really love to know a way to change a pciture without it flickering as some really cool controls could be made with these icos.
Flicker can often be removed by sub-classing the control and blocking WM_ERASEBKGND messages.
majkinetor wrote:
I wonder if such speed can be acomplished with same algorythm in AutoIt or VBscript.
I wonder if VBscript is capable of generating icons at all. Shocked
Back to top
View user's profile Send private message Visit poster's website
tic



Joined: 22 Apr 2007
Posts: 1786

PostPosted: Thu Nov 29, 2007 8:02 pm    Post subject: Reply with quote

Quote:
Flicker can often be removed by sub-classing the control and blocking WM_ERASEBKGND messages.


Huh? How do you do that? Confused

http://www.catch22.net/tuts/flicker.asp

dont know what to do

Edit: Being hasty on the "i dont understand front" Smile

Code:
#Persistent
SetWorkingDir %A_ScriptDir%               ; Ensure working directory is used so that icon location is know
#Include tic-MakeICOBars-1.10.ahk

OnMessage(0x200, "WM_MOUSEMOVE")
OnMessage(0x0014, "WM_ERASEBKGND")
SoundGet, Volume
MakeICOBars(Volume, "ff0000", "Vol.ico")

Gui, 1: +LastFound
Gui1 := WinExist()
Gui, 1: Add, Picture, x10 y10 w256 h256 vVolControl, Vol.ico
Gui, 1: Show, AutoSize, Volume Control
ControlGetPos, CX, CY, CW, CH, Static1
Return

WM_MOUSEMOVE()
{
   Global
   
   MouseGetPos, HX, HY, HWin, HControl   
   If HControl = Static1
   {      
      Loop
      {
         Sleep, 25
         GetKeyState, LButtonState, LButton
         If LButtonState = U
         Return
         
         MouseGetPos, HX, HY, HWin, HControl
         If ((Round(100*((CH-(HY-CY))/ CH)) > StorePerc+5) || (Round(100*((CH-(HY-CY))/ CH)) < StorePerc-5)) && (HY < CH+CY) && (HY > CY)
         {
            GuiControl, Hide, VolControl
            MakeICOBars(Round(100*((CH-(HY-CY))/ CH)), "ff0000", "Vol.ico")
            GuiControl,, VolControl, Vol.ico
            GuiControl, Show, VolControl
            StorePerc := Round(100*((CH-(HY-CY))/ CH))
            SoundSet, % Round(100*((CH-(HY-CY))/ CH))
         }
      }
   }
   Return
}

WM_ERASEBKGND()
{

   Return, 1
}

Esc::ExitApp


Much better but still slightly flickery. Any more ideas how to cut the flicker?
Some very nice new controls could be made with this
Back to top
View user's profile Send private message
Andreone



Joined: 20 Jul 2007
Posts: 257
Location: Paris, France

PostPosted: Thu Nov 29, 2007 8:18 pm    Post subject: Reply with quote

tic wrote:
Huh? How do you do that? Confused
Majekinor has written some time ago an example of subclassing here AbstractCombo
The concept is to change the default callback (function pointer) of a window by yours, thus you can filter the messages it receives and finally change its behavior.
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Thu Nov 29, 2007 8:51 pm    Post subject: Reply with quote

tic wrote:
the machine code is creating 32pixel icos not 16 (so they can be added as pictures as well)

Btw, I edited my code to show a) it's easy to change the icon size, and b) it's easy to add it to a GUI. If you're using it on a GUI, you'd probably want to either draw directly onto the GUI or use the generated bitmap without generating an icon (especially since icon sizes may be restricted.) For simplicity, my example uses the icon. A lot of speed is lost (with bigger images) in the loop that calculates alpha data. GDI+ would be faster, as would AlphaBlend (which would require you to create a bitmap for the background, but would not require GDI+.) Alternatively, you could replace the loop with a machine code function. Razz

I suppose another advantage of using GDI or GDI+ is that you could draw images, not just bars...
Quote:
How do you do that?

See SetWindowLong.
Quote:
Calling SetWindowLong with the GWL_WNDPROC index creates a subclass of the window class used to create the window. An application can subclass a system class, but should not subclass a window class created by another process. The SetWindowLong function creates the window subclass by changing the window procedure associated with a particular window class, causing the system to call the new window procedure instead of the previous one. An application must pass any messages not processed by the new window procedure to the previous window procedure by calling CallWindowProc. This allows the application to create a chain of window procedures.
Back to top
View user's profile Send private message Visit poster's website
majkinetor



Joined: 24 May 2006
Posts: 4511
Location: Belgrade

PostPosted: Thu Nov 29, 2007 9:01 pm    Post subject: Reply with quote

Code:
Gui, 1: Add, Picture, x10 y10 w256 h256 vVolControl HWNDhCtrl, Vol.ico


WindowProcNew := RegisterCallback("WindowProc", "F")
WindowProcOld := DllCall("SetWindowLong", "UInt", hCtrl, "Int", -4, "Int", WindowProcNew, "UInt")
Return

WindowProc(hwnd, uMsg, wParam, lParam){
   global WindowProcOld

   if (uMsg = 0x14)
      return 0

   res := DllCall("CallWindowProcA", "UInt", WindowProcOld, "UInt", hwnd, "UInt", uMsg, "UInt", wParam, "UInt", lParam)

   return res
}

This, unfortunately doesn't solve the problem. Flickering can be solved by directly drawin icon on the DC. For that, you need to return us handle of the icon, not the file. I suggest your function to return hIcon if user passes empty string for icon name, or 0 if not succeiful.

Speaking about your "Volume Control" example, you can use Tray module to make changing the volume possible directly from tray. It can watch mouse moves, so you can update the icon in tray the same way you do it in GUI. You can even make horizontal, larger volume line, by monitoring mouse moves over two or more icons Smile

BTW, CPU monitor example looks very nice.
_________________
Back to top
View user's profile Send private message
tic



Joined: 22 Apr 2007
Posts: 1786

PostPosted: Thu Nov 29, 2007 11:59 pm    Post subject: Reply with quote

Ive fixed some very minor errors I found, and improved the examples so they flicker less (not uploaded yet), but as you want it so much Smile what do you think would be the best way to retrive the hIcon rather than writing to file? Ill add it in if I can get a nice way of doing it, and I think the syntax should be that if you specify hIcon and then the name of the handle, then it will put hIcon into the handle, as i find having those errorlevels very useful.

Example:

Code:
MakeICOBars("25|50", "ff0000|0000ff", "hIcon Handle")


I hope you like the neater version of my code and that my commenting is adequate.

Also I think the cpu shifting example looks better if set to 150 timer rather than 250
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 7299
Location: Australia

PostPosted: Fri Nov 30, 2007 2:52 am    Post subject: Reply with quote

It seems most of the flickering is actually caused by GuiControl invalidating the GUI itself. Try using STM_SETICON (0x170) or STM_SETIMAGE (0x172) to set the icon/bitmap instead. You'll probably find that it flickers much less, but still occasionally flickers. LoadImage() can be used to get a HICON from file.
Quote:
improved the examples so they flicker less
I'm curious... how?

Sometimes the only way to remove flicker entirely is to do all the drawing yourself (i.e. handle WM_PAINT.) For some controls you can cheat by printing the control into a buffer (an in-memory bitmap) using PrintWindow or WM_PRINT, then painting the buffer onto the window.

Edit: The remaining flicker happens because the picture control paints the background each time it paints the icon. Since it does both operations directly on the window, occasionally the window updates after the background is drawn, but before the icon is finished. The solution is to override WM_PAINT.

The following example should be entirely flicker-free:
Code:
Gui, Add, Picture, vIcon hwndhPic w256 h256 icon4, %A_AhkPath%
WindowProcNew := RegisterCallback("WindowProc")
WindowProcOld := DllCall("SetWindowLong","uint",hPic,"int",-4,"int",WindowProcNew,"uint")
Gui, Show
SetTimer, switch, 100
Return

switch:
    ; Load an icon from the current executable.
    hicon := DllCall("LoadImage","uint",DllCall("GetModuleHandle","uint",0)
        ,"uint",(s:=!s) ? 208:207,"uint",1,"int",256,"int",256,"uint",0)
    if !hicon
        return
    ; Set the icon.
    SendMessage, 0x170, hicon,,, ahk_id %hPic%
    ; Destroy the previous icon.
    if ErrorLevel
        DllCall("DestroyIcon","uint",ErrorLevel)
return

GuiClose:
ExitApp

WindowProc(hwnd, uMsg, wParam, lParam)
{
    global WindowProcOld
    Critical 500 ; Must ensure AutoHotkey doesn't check for messages.
   
    if (uMsg = 0x14)
        return 1
   
    if (uMsg = 0xF)
    {
        WinGetPos,,, w, h, ahk_id %hwnd%
        VarSetCapacity(ps,64,0)
        DllCall("BeginPaint","uint",hwnd,"uint",&ps)
        hdc := NumGet(ps,0)
        if hicon := CallWindowProc(WindowProcOld, hwnd, 0x171,0,0) ; STM_GETICON
        {
            ; Get a brush to be used as the background.
            hbr := DllCall("GetSysColorBrush","int",15)
            ; DrawIconEx draws the background and icon into a temporary buffer,
            ; then draws the buffer onto the window. (It draws directly onto the
            ; window if hbr is not a valid brush handle.)
            DllCall("DrawIconEx","uint",hdc,"int",0,"int",0,"uint",hicon
                ,"int",w,"int",h,"uint",0,"uint",hbr,"uint",0x3)
        }
        DllCall("EndPaint","uint",hwnd,"uint",&ps)
        return 0
    }
   
    res := CallWindowProc(WindowProcOld, hwnd, uMsg, wParam, lParam)
   
    return res
}

CallWindowProc(wndProc, hwnd, uMsg, wParam, lParam) {
    return DllCall("CallWindowProc","uint",wndProc,"uint",hwnd,"uint",uMsg,"uint",wParam,"uint",lParam)
}
If you comment out these two lines:
Code:
WindowProcNew := RegisterCallback("WindowProc")
WindowProcOld := DllCall("SetWindowLong","uint",hPic,"int",-4,"int",WindowProcNew,"uint")
...it should flicker less than it would with GuiControl, but still occasionally "blink."

A typical control paints everything in WM_PAINT, but if you find it easier to pre-generate the icon and paint only that from WM_PAINT, you may as well.
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page Previous  1, 2, 3, 4  Next
Page 3 of 4

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group