This is a
Spinner control, to inform the user that a lengthy process or critical task is running.
(http://www.zapsolution.com/pictures/spinner.jpg)
This controls is provided on the form of a PB10
.SLL file to be imbedded within an EXE or DLL.
The graphic resource animations are stored in a dedicated folder to ease their customization.
The spinner itself uses a distinct thread, it is top-most and auto-centered in the parent window.
Note: The
zSpinnerInit function returns the Spinner window handle as a DWORD.
The resource animations are using the GDImage/WinLIFT proprietary image format with the .SKI extension, however you can still use the .PNG extension.
Added:
- CPU reduction + nSpeedDelay parameter to customize the speed animation.
...
Forget to say, that you can move the spinner around, if you are able to catch it with the mouse ;)
...
Hi Patrice,
When trying to compile it with my headers, I get error 632: GetModuleHandle: COMMON NAME IS A DUPLICATE.
Do you have compiled the SLL using your own declarations and declaring GetModuleHandle as COMMON ?
José,
I am always compiling from a DOS prompt using COMPILE.BAT like this:
D:\PowerTry\PBWIN /I.\; D:\PowerTry\Jose_WinAPI %1
However in zSpin.sll i am using my own headers, to produce the smallest code, whatever the PowerBASIC version being used.
So far i am only using PB10 for test, and i stay with PB9 for all my code production.
'+--------------------------------------------------------------------------+
'| |
'| zSpin 1.00 |
'| |
'| Animated spinner control |
'| |
'+--------------------------------------------------------------------------+
'| |
'| Author Patrice TERRIER |
'| |
'| copyright(c) 2011-2011 |
'| |
'| Patrice Terrier http://www.zapsolution.com |
'| |
'+--------------------------------------------------------------------------+
'| Project started on : 04-11-2011 (MM-DD-YYYY) |
'| Last revised : 04-11-2011 (MM-DD-YYYY) |
'+--------------------------------------------------------------------------+
#COMPILE SLL "zSpin.sll"
'----------------------------------------------------------------------
%TRUE = 1
%FALSE = 0
%NULL = 0
%IDC_ARROW = 32512&
%CS_VREDRAW = &H1
%CS_HREDRAW = &H2
%HTCAPTION = 2
%WM_CREATE = &H1
%WM_TIMER = &H113
%WM_NCHITTEST = &H084
%WM_DESTROY = &H2
%AC_SRC_OVER = &H00
%AC_SRC_ALPHA = &H01
%ULW_ALPHA = &H00000002
TYPE BLENDFUNCTION
BlendOp AS BYTE
BlendFlags AS BYTE
SourceConstantAlpha AS BYTE
AlphaFormat AS BYTE
END TYPE
TYPE SIZEL
cx AS LONG
cy AS LONG
END TYPE
TYPE RECT
nLeft AS LONG
nTop AS LONG
nRight AS LONG
nBottom AS LONG
END TYPE
TYPE POINTAPI
x AS LONG
y AS LONG
END TYPE
TYPE tagMSG
hwnd AS DWORD
message AS DWORD
wParam AS LONG
lParam AS LONG
time AS DWORD
pt AS POINTAPI
END TYPE
TYPE WNDCLASSEX
cbSize AS DWORD
style AS DWORD
lpfnWndProc AS LONG
cbClsExtra AS LONG
cbWndExtra AS LONG
hInstance AS DWORD
hIcon AS DWORD
hCursor AS DWORD
hbrBackground AS DWORD
lpszMenuName AS ASCIIZ PTR
lpszClassName AS ASCIIZ PTR
hIconSm AS DWORD
END TYPE
DECLARE FUNCTION GetModuleHandle LIB "KERNEL32.DLL" ALIAS "GetModuleHandleA" (lpModuleName AS ASCIIZ) AS DWORD
DECLARE FUNCTION FindWindow LIB "USER32.DLL" ALIAS "FindWindowA" (lpClassName AS ASCIIZ, lpWindowName AS ASCIIZ) AS LONG
DECLARE SUB apiSleep LIB "KERNEL32.DLL" ALIAS "Sleep" (BYVAL dwMilliseconds AS DWORD)
DECLARE FUNCTION GetWindowRect LIB "USER32.DLL" ALIAS "GetWindowRect" (BYVAL hWnd AS DWORD, lpRect AS RECT) AS LONG
DECLARE FUNCTION MoveWindow LIB "USER32.DLL" ALIAS "MoveWindow" (BYVAL hWnd AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG, BYVAL bRepaint AS LONG) AS LONG
DECLARE FUNCTION KillTimer LIB "USER32.DLL" ALIAS "KillTimer" (BYVAL hWnd AS DWORD, BYVAL nIDEvent AS LONG) AS LONG
DECLARE FUNCTION SetTimer LIB "USER32.DLL" ALIAS "SetTimer" (BYVAL hWnd AS DWORD, BYVAL nIDEvent AS LONG, BYVAL uElapse AS DWORD, BYVAL lpTimerFunc AS LONG) AS LONG
DECLARE FUNCTION GetClassInfoEx LIB "USER32.DLL" ALIAS "GetClassInfoExA" (BYVAL hInst AS DWORD, lpszClass AS ASCIIZ, lpWndClass AS WNDCLASSEX) AS LONG
DECLARE FUNCTION RegisterClassEx LIB "USER32.DLL" ALIAS "RegisterClassExA" (pcWndClassEx AS WNDCLASSEX) AS WORD
DECLARE FUNCTION CreateWindowEx LIB "USER32.DLL" ALIAS "CreateWindowExA" (BYVAL dwExStyle AS DWORD, lpClassName AS ASCIIZ, lpWindowName AS ASCIIZ, BYVAL dwStyle AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG, _
BYVAL nWidth AS LONG, BYVAL nHeight AS LONG, BYVAL hWndParent AS DWORD, BYVAL hMenu AS DWORD, BYVAL hInstance AS DWORD, lpParam AS ANY) AS DWORD
DECLARE FUNCTION UpdateWindow LIB "USER32.DLL" ALIAS "UpdateWindow" (BYVAL hWnd AS DWORD) AS LONG
DECLARE FUNCTION GetMessage LIB "USER32.DLL" ALIAS "GetMessageA" (lpMsg AS tagMSG, BYVAL hWnd AS DWORD, BYVAL uMsgFilterMin AS DWORD, BYVAL uMsgFilterMax AS DWORD) AS LONG
DECLARE FUNCTION IsDialogMessage LIB "USER32.DLL" ALIAS "IsDialogMessageA" (BYVAL hDlg AS DWORD, lpMsg AS tagMSG) AS LONG
DECLARE FUNCTION TranslateMessage LIB "USER32.DLL" ALIAS "TranslateMessage" (lpMsg AS tagMSG) AS LONG
DECLARE FUNCTION DispatchMessage LIB "USER32.DLL" ALIAS "DispatchMessageA" (lpMsg AS tagMSG) AS LONG
DECLARE FUNCTION GetDC LIB "USER32.DLL" ALIAS "GetDC" (BYVAL hWnd AS DWORD) AS DWORD
DECLARE FUNCTION UpdateLayeredWindow LIB "USER32.DLL" ALIAS "UpdateLayeredWindow" (BYVAL hWnd AS DWORD, BYVAL hdcDst AS DWORD, pptDst AS POINTAPI, psize AS SIZEL, BYVAL hdcSrc AS DWORD, pptSrc AS POINTAPI, _
BYVAL crKey AS DWORD, pblend AS BLENDFUNCTION, BYVAL dwFlags AS DWORD) AS LONG
DECLARE FUNCTION ReleaseDC LIB "USER32.DLL" ALIAS "ReleaseDC" (BYVAL hWnd AS DWORD, BYVAL hDC AS DWORD) AS LONG
DECLARE FUNCTION LoadCursor LIB "USER32.DLL" ALIAS "LoadCursorA" (BYVAL hInstance AS DWORD, lpCursorName AS ASCIIZ) AS DWORD
DECLARE SUB PostQuitMessage LIB "USER32.DLL" ALIAS "PostQuitMessage" (BYVAL nExitCode AS LONG)
DECLARE FUNCTION DefWindowProc LIB "USER32.DLL" ALIAS "DefWindowProcA" (BYVAL hWnd AS DWORD, BYVAL uMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
DECLARE FUNCTION DestroyWindow LIB "USER32.DLL" ALIAS "DestroyWindow" (BYVAL hWnd AS DWORD) AS LONG
DECLARE FUNCTION CreateCompatibleDC LIB "GDI32.DLL" ALIAS "CreateCompatibleDC" (BYVAL hdc AS DWORD) AS DWORD
DECLARE FUNCTION CreateCompatibleBitmap LIB "GDI32.DLL" ALIAS "CreateCompatibleBitmap" (BYVAL hdc AS DWORD, BYVAL nWidth AS LONG, BYVAL nHeight AS LONG) AS DWORD
DECLARE FUNCTION SelectObject LIB "GDI32.DLL" ALIAS "SelectObject" (BYVAL hdc AS DWORD, BYVAL hObject AS DWORD) AS DWORD
DECLARE FUNCTION DeleteObject LIB "GDI32.DLL" ALIAS "DeleteObject" (BYVAL hObject AS DWORD) AS LONG
DECLARE FUNCTION DeleteDC LIB "GDI32.DLL" ALIAS "DeleteDC" (BYVAL hdc AS DWORD) AS LONG
DECLARE FUNCTION GetDesktopWindow LIB "USER32.DLL" ALIAS "GetDesktopWindow" () AS LONG
DECLARE FUNCTION IsWindow LIB "USER32.DLL" ALIAS "IsWindow" (BYVAL hWnd AS DWORD) AS LONG
DECLARE FUNCTION SetThreadPriority LIB "KERNEL32.DLL" ALIAS "SetThreadPriority" (BYVAL hThread AS DWORD, BYVAL nPriority AS LONG) AS LONG
DECLARE FUNCTION zTrace LIB "zTrace.DLL" ALIAS "zTrace" (zMessage AS ASCIIZ) AS LONG
...
It works if the declares use
#IF %DEF(%UNICODE)
DECLARE FUNCTION GetModuleHandle IMPORT "KERNEL32.DLL" ALIAS "GetModuleHandleA" ( _
BYREF lpModuleName AS ASCIIZ _ ' __in LPCSTR lpModuleName
) AS DWORD ' HMODULE
#ELSE
DECLARE FUNCTION GetModuleHandle IMPORT "KERNEL32.DLL" ALIAS "GetModuleHandleW" ( _
BYREF lpModuleName AS WSTRINGZ _ ' __in LPCWSTR lpModuleName
) AS DWORD ' HMODULE
#ENDIF ' NOT %UNICODE
but not if they use
DECLARE FUNCTION GetModuleHandleA IMPORT "KERNEL32.DLL" ALIAS "GetModuleHandleA" ( _
BYREF lpModuleName AS ASCIIZ _ ' __in LPCSTR lpModuleName
) AS DWORD ' HMODULE
DECLARE FUNCTION GetModuleHandleW IMPORT "KERNEL32.DLL" ALIAS "GetModuleHandleW" ( _
BYREF lpModuleName AS WSTRINGZ _ ' __in LPCWSTR lpModuleName
) AS DWORD ' HMODULE
#IF %DEF(%UNICODE)
MACRO GetModuleHandle = GetModuleHandleW
#ELSE
MACRO GetModuleHandle = GetModuleHandleA
#ENDIF
I have posted it in the beta forum. Let's see what Bob says.
Thank you Patrice, Very cool !! :)
Doug
As always Patrice, you deliver delicious code!!!
Many Thanks!
Best Regards,
Jules
I have attached to this post a set of new spinner animations.
Most of them are meant to be used hover a dark (black) bakground.
Enjoy!
...
Some i wanted to keep for myself...
but i couldn't resist to share them with you ;)
...
Here is a new one i have done.
Fascinating on a dark background...
Imagine, just dreaming...
Must be used on a dark background.
A .ski file is an acronym for "Skin Image", it is an ARGB 32-bit lossless compressed GDImage proprietary format, intended to be used with the WinLIFT Skin Engine.
Its main purpose is to protect the design artwork of graphic creators.
Each Skin theme, and also each Spinner, is the result of several hours (even days) of Photoshop work.
...
Amazing!
New spinner pack:
- fireworks.ski
- heal.ski
- light003.ski
- light004.ski
- magic.ski
- magic_003.ski
- triangle.ski
You can stop Patrice, any Opponen was out of the market already after your last strike :D
Your creativity is unbeaten as i see it.
Here are two more spinners.
- blackblob.ski
- watertore.ski
Theo--
ski spinners are working in full composited mode using variable opacity, it means they can render glass and transparent marerial, just like real objects.
...
Thanks, i may really use them in my next project!
This your artwork is so amazing.
Btw. The watertore.ski has a slight bug: See attached picture.
Theo
The credit must also be given to all the artists worlwide publishing their artwork for free on the web.
For example look at this one:
http://www.thisiscolossal.com/2013/07/carl-warner-bodyscapes/?src=footer
Theo
Thanks for the report, i have reworked the watertore.ski, and it is attached to this post.
...
If its about finding bugs you can count on me Patrice. ;D
This is not bad intention, but i take a closer look on a program, the bugs easily open up to me.
Even if i am not searching.
But let me say that your software is very clean and alltogether unbeaten from a design standpoint from what i have seen until now.
This is not what i would call a bug, because it is not software related, just a few frames of the original graphic animation that i forget to edit with Photoshop to setup the alpha channel of the layer to NULL.
My eyes do not have anymore the accuracy they had... before i started full time programming 35 years ago ;)
Seen like this, your stuff is bug free. This is what people in this forum expect.
This is how PowerBasic was many years, this is why most people are here.
These are based on the work of PATAKK, alias Paolo Ceric, from Zagreb Croatia.
The original where GIF files, but i translated all of them to work in full GDImage transparent composited mode, then i reworked each of them with Photoshop to produce these fine 6 spinners.
My favorite one is: Crystal.ski, but i also like the others, or i won't have spent one full day to create them ;)
(http://www.zapsolution.com/pictures/patakk.jpg)
Patrice, very nice job on zSpinPB10.sll. As an aside, I added a dir scan to your test file (below), and put all the SKI files into the "SpinFolder" so I could just press enter and enjoy. I noticed that I can't click "thru" the animations, sometimes I have to move them out of the way to click the OK button.
#COMPILE EXE "SpinTest.exe"
'DECLARE FUNCTION zSpinnerInit LIB "zSpin.dll" ALIAS "zSpinnerInit" (BYVAL hParent AS DWORD, zTmp AS ASCIIZ, BYVAL nSpeedDelay AS LONG) AS DWORD
'DECLARE SUB zSpinnerClose LIB "zSpin.dll" ALIAS "zSpinnerClose" ()
'#LINK "zSpin.sll"
#LINK "zSpinPB10.sll"
FUNCTION PBMAIN
LOCAL hParent AS DWORD
LOCAL nSpeedDelay AS LONG
LOCAL SpinFolder, sCaption AS STRING
hParent = 0
sCaption = "Spinner"
SpinFolder = EXE.PATH$ + "SpinFolder\"
DIM Listing(1 TO 1) AS WSTRING
LOCAL dwCount, x AS DWORD
dwCount = DirScan(SpinFolder & "*", Listing())
FOR x = 1 TO dwCount
CALL zSpinnerInit(hParent, SpinFolder & Listing(x), 0)
MSGBOX Listing(x), , Listing(x)
NEXT x
CALL zSpinnerClose()
END FUNCTION
FUNCTION DirScan(BYVAL sMask AS WSTRING, BYREF Listing() AS WSTRING) AS DWORD
' sMask = "*"
' Listing() will be populated
LOCAL x AS DWORD
LOCAL a AS WSTRING
x = 0
a = DIR$(sMask,7) ' 7 for files, 16 for folders, 23 for files and folders
WHILE LEN(a)
INCR x
REDIM PRESERVE Listing(1 TO x)
Listing(x) = a
a = DIR$(NEXT)
WEND
DIR$ CLOSE
FUNCTION = x
END FUNCTION
I wrote a small command line utility to run any spinner from a DOS prompt (or shell)
You can specify the speed of the animation at the time you start the spinner this way:
C:\Spinner\FWS.exe d:\SpinnerFolder\crystal.ski;33
;33 is the speed in ticks count per second ranging from 1 to any value.
note: there is 1000 ticks per second.
If you do not specify a speed value, then it will use the default animation speed for that spinner.
To close a running spinner, select it, then press the ESC key, or press ALT+F4
Note: You can run multiple instance of FWS.
...
I know you will love... her
Hahaha is it Power Vivans daughter :-)?
Theo--
No, she is her grand daughter :)
Three more 3D based, using variable opacity .
(http://www.zapsolution.com/pictures/3more3d.jpg)
This one is based on the work of Matthew Brand.
Five hours of Photoshop's work to clean up the original gif file, i must be crazy :)
...
Meditation, will lead you to God's karma...
No screen shot, you wil have to try it, to figure out :)
...
The Zen man, is nice to tell your user that he must wait a little...
Butterfly, would always pleased to the ladies.
And spiral_knot, are for the geek like myself.
(http://www.zapsolution.com/pictures/Zen.jpg)
These are amazing, Patrice. Awesome work!
Karma ... Zen. Are we going the spiritual way, Patrice?
Your Work is awesome as always.
PS: Don't try to improve, in your expertise you have reached a level that you can not beat.
Brice, Theo,
thanks.
I should have some more on my back burner...
As an answer to Randall Glass
Here is a transparent png, using variable opacity, to use it, just drag and drop "broken_glass.png" onto FWS.exe.
In order to get rid of it, select the image, then press the ESCAPE key, or ALT-F4.
By the way that shows you that FWS.exe is able to display static image as well as animation, as long as the image fit within a square (same width and height).
...
Here is a melting pot:
- GreenEffect
- LightDrop
- PleaseWait
- Shade01
- Shade02
- Shade03
- Water01
(http://www.zapsolution.com/pictures/meltingpot.jpg)
I love the water one. ;D
Hi Patrice,
I would like to know where I can find the latest version of your Spinner Control.
Did you encountered some issues using it with Windows 10 ?
Thanks
Jean-Pierre
Jean Pierre
What's your problem with Windows 10 ?
...
I use the Spinner control on Windows 10 with a dual screen:
- When hParent value is 0 the animation is displayed everytime (perfect) but on the main screen (which is normal).
- When hParent is the handle of the main form of my application, the animation is not displayed everytime: sometimes yes sometimes no; I don't know why.
PS: I use the Spinner control with FireFly; I don't know if that could be related or not.
Regards,
Jean-Pierre
Jean-Pierre
I am using nothing fancy, just the regular MoveWindow API to center the spinner control within the window rectangle of its parent like this:
IF ghWnd THEN
LOCAL rw AS RECT
CALL GetWindowRect(hParent, rw)
CALL MoveWindow(ghWnd, rw.nLeft + ((rw.nRight - rw.nLeft - gnH) * 0.5), rw.nTop + ((rw.nBottom - rw.nTop - gnH) * 0.5), gnH, gnH, 0)
SELECT CASE LONG gnFrameCount ' Compute animation's speed
CASE < 4: gnUseSpeed = 300
CASE < 8: gnUseSpeed = 200
CASE < 12: gnUseSpeed = 150
CASE < 20: gnUseSpeed = 100
CASE ELSE: gnUseSpeed = 60
END SELECT
CALL SetTimer(ghWnd, 1, gnUseSpeed * 0.5, %NULL)
END IF
ghWnd is the handle of the spinner control, while hParent is the handle of the parent being used when you call zSpinnerInit.
I have no idea of what FireFly is doing, i stop using it since the introduction of the CWindow class that also breaks the WinLIFT code.
No problem by me with multiple monitors, but i am using the one from GDImage (ZI_SpinnerInit) that is a regular DLL.
The best i can do, is to send you the source code that was used to create the SLL.
To detect if that is a FireFly problem or not, just create an empty window with a single button to fire the control once you have moved the main window to the secondary display.
Also you must be aware that there is a random memory error with the latest PB's version that has never been fixed.
(REDIM, ARRAY SCAN)
...
Patrice thank you for you answer.
I made the test with an empty window with a single button to fire the control: it works :)
So It could be something else in my source code ;D
Thanks,
Jean-Pierre