I updated the gif because the old one had some bad frames, but this is unrelated to the question
I would like to disable the play once button when the animation starts and enable when it ends.
Like I said, the code is beyond me at the moment but I'm learning.
I added to the class and the part to disable works, but the part to enable does not even though it does trigger a message box when the animation is done
The complete code with my changes (line 111 and 116-118) maybe there is another way to do this?
Code: Select all
SetBatchLines, -1
gifFile := "welcome.gif"
exStyles := (WS_EX_COMPOSITED := 0x02000000) | (WS_EX_LAYERED := 0x80000)
Gui, New, +E%exStyles%
gui, color, black
Gui, Add, Picture, w480 y10 hwndhwndGif1 +BackgroundTrans, % gifFile
Gui, Add, Button, xp y+10 w80 h24 gPlay vPlaybtn, Play Once
UserFunc := Func("PlayGif").Bind(hwndGif1)
MyGif := new AnimateGif(gifFile, UserFunc, false)
Gui, Show,, Animated gif
Return
Play:
MyGif.Play()
Return
PlayGif(hPic, currentFrameIdx, hBitmap) {
GuiControl,, % hPic, HBITMAP: %hBitmap%
}
GuiClose() {
ExitApp
}
class AnimateGif
{
; UserFunc will be called with two params: currentFrameIdx and hBitmap
; user is responsible for deleting hBitmap
__New(gifFile, UserFunc := "", cycle := true) {
this.GDIp := new GDIplus
this.pBitmap := this.GDIp.CreateBitmapFromFile(gifFile)
this.Frames := new this._FramesHandling(this.GDIp, this.pBitmap, UserFunc, cycle)
this.GDIp.GetImageDimensions(this.pBitmap, width, height)
this.width := width
this.height := height
}
Play() {
this.playing := true
this.Frames.PlayFrames()
}
Pause() {
if this.playing {
this.playing := false
timer := this.Frames._PlayTimer
SetTimer, % timer, Delete
}
}
Stop() {
this.Pause()
this.ShowFrame(1)
}
Prev() {
this.ShowFrame("prev")
}
Next() {
this.ShowFrame("next")
}
ShowFrame(which) { ; 'which' can be "prev", "next" or "", or 1-based frame index
this.Pause()
(which = "prev" && this.Frames.currentFrame -= 2)
(which + 0 && this.Frames.currentFrame := which - 1)
this.Frames.PlayFrames()
}
GetFrameByIndex(idx) {
Return hBitmap := this.Frames.GetFrame(idx - 1)
}
playing[] {
get {
Return this.Frames.playing
}
set {
Return this.Frames.playing := value
}
}
framesCount[] {
get {
Return this.Frames.frameCount
}
}
__Delete() {
this.Frames.Clear()
this.GDIp.DisposeImage(this.pBitmap)
this.Delete("Frames")
this.GDIp.Release()
}
class _FramesHandling {
__New(GDIp, pBitmap, userFunc, cycle) {
this.GDIp := GDIp
this.pBitmap := pBitmap
this.userFunc := userFunc
this.cycle := cycle
this.GetFrameCount()
this.GetFrameDelay()
this._PlayTimer := ObjBindMethod(this, "PlayFrames")
this._currentFrame := 1
}
currentFrame[] {
get {
Return this._currentFrame
}
set {
Return this._currentFrame := value < 1 ? this.frameCount + value : value > this.frameCount ? 1 : value
}
}
PlayFrames() {
Critical
guicontrol, disable, Playbtn
frameIdx := ++this.currentFrame - 1
if ( this.playing && this.currentFrame != (this.cycle ? 0xFFFFFFFF : this.frameCount) ) {
timer := this._PlayTimer
SetTimer, % timer, % "-" this.frameDelay[frameIdx]
} else {
MsgBox, done
guicontrol, enable, Playbtn
}
if userFunc := this.userFunc
%userFunc%(this.currentFrame, this.GetFrame(frameIdx))
}
GetFrameCount() {
this.frameCount := this.GDIp.GetFrameCount(this.pBitmap, dimensionIDs, size)
this.SetCapacity("dimensionIDs", size)
this.pDimensionIDs := this.GetAddress("dimensionIDs")
DllCall("RtlMoveMemory", "Ptr", this.pDimensionIDs, "Ptr", &dimensionIDs, "Ptr", size)
VarSetCapacity(dimensionIDs, 0), dimensionIDs := ""
this.currentFrame := 0
}
GetFrameDelay() {
this.GDIp.GetPropertyItem(this.pBitmap, PropertyTagFrameDelay := 0x5100, item)
len := NumGet(item, 4, "UInt")
val := NumGet(item, 8 + A_PtrSize, "UPtr")
this.frameDelay := []
Loop, % len//4 {
i := A_Index - 1
n := NumGet(val + i*4, "UInt") * 10
this.frameDelay[i] := n ? n : 100
}
}
GetFrame(idx) {
this.GDIp.ImageSelectActiveFrame(this.pBitmap, this.pDimensionIDs, idx)
Return this.GDIp.CreateHBITMAPFromBitmap(this.pBitmap)
}
Clear() {
this.playing := false
timer := this._PlayTimer
SetTimer, % timer, Delete
this.Delete("dimensionIDs")
}
}
}
class GDIplus {
__New() {
static Instance := ""
if Instance.references {
++Instance.references
Return Instance
}
this.references := 1
if !DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
DllCall("LoadLibrary", "Str", "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", "UPtrP", pToken, "Ptr", &si, "Ptr", 0)
this.token := pToken
Return Instance := this
}
Release() {
if --this.references
Return
DllCall("gdiplus\GdiplusShutdown", "Ptr", this.token)
if hModule := DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
DllCall("FreeLibrary", "Ptr", hModule)
}
CreateBitmapFromFile(sFile) {
DllCall("gdiplus\GdipCreateBitmapFromFile", "WStr", sFile, "PtrP", pBitmap)
Return pBitmap
}
CreateHBITMAPFromBitmap(pBitmap, Background=0xffffffff) {
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "PtrP", hbm, "Int", Background)
Return hbm
}
GetImageDimensions(pBitmap, ByRef Width, ByRef Height) {
DllCall("gdiplus\GdipGetImageWidth", "Ptr", pBitmap, "UIntP", Width)
DllCall("gdiplus\GdipGetImageHeight", "Ptr", pBitmap, "UIntP", Height)
}
GetFrameCount(pBitmap, ByRef dimensionIDs, ByRef size) {
DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "Ptr", pBitmap, "UIntP", frameDimensions)
VarSetCapacity(dimensionIDs, size := 16*frameDimensions)
DllCall("gdiplus\GdipImageGetFrameDimensionsList", "Ptr", pBitmap, "Ptr", &dimensionIDs, "UInt", frameDimensions)
DllCall("gdiplus\GdipImageGetFrameCount", "Ptr", pBitmap, "Ptr", &dimensionIDs, "UIntP", count)
Return count
}
GetPropertyItem(pBitmap, tag, ByRef item) {
DllCall("gdiplus\GdipGetPropertyItemSize", "Ptr", pBitmap, "UInt", tag, "UIntP", size)
VarSetCapacity(item, size, 0)
DllCall("gdiplus\GdipGetPropertyItem", "Ptr", pBitmap, "UInt", tag, "UInt", size, "Ptr", &item)
Return size
}
ImageSelectActiveFrame(pBitmap, pDimensionIDs, idx) {
Return DllCall("gdiplus\GdipImageSelectActiveFrame", "Ptr", pBitmap, "Ptr", pDimensionIDs, "Int", idx)
}
DisposeImage(pBitmap) {
Return DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
}
}
Code: Select all
PlayFrames() {
Critical
guicontrol, disable, Playbtn ; this works
frameIdx := ++this.currentFrame - 1
if ( this.playing && this.currentFrame != (this.cycle ? 0xFFFFFFFF : this.frameCount) ) {
timer := this._PlayTimer
SetTimer, % timer, % "-" this.frameDelay[frameIdx]
} else {
MsgBox, done ; this works
guicontrol, enable, Playbtn ; this does not work
}
if userFunc := this.userFunc
%userFunc%(this.currentFrame, this.GetFrame(frameIdx))
}
Code: Select all
SetBatchLines, -1
gifFile := "welcome.gif"
exStyles := (WS_EX_COMPOSITED := 0x02000000) | (WS_EX_LAYERED := 0x80000)
Gui, New, +E%exStyles%
gui, color, black
Gui, Add, Picture, w480 y10 hwndhwndGif1 +BackgroundTrans, % gifFile
Gui, Add, Button, xp y+10 w80 h24 gPlay vPlaybtn, Play Once
UserFunc := Func("PlayGif").Bind(hwndGif1)
MyGif := new AnimateGif(gifFile, UserFunc, false)
numberOfFrames := MyGif.framesCount()
Gui, Show,, Animated gif
Return
Play:
guicontrol, disable, Playbtn
MyGif.Play()
Return
PlayGif(hPic, currentFrameIdx, hBitmap) {
global numberOfFrames
GuiControl,, % hPic, HBITMAP: %hBitmap%
if (currentFrameIdx = numberOfFrames) {
MsgBox done ; works
guicontrol, enable, Playbtn ; dont work
}
tooltip, % currentFrameIdx " - " numberOfFrames
}
GuiClose() {
ExitApp
}
class AnimateGif
{
; UserFunc will be called with two params: currentFrameIdx and hBitmap
; user is responsible for deleting hBitmap
__New(gifFile, UserFunc := "", cycle := true) {
this.GDIp := new GDIplus
this.pBitmap := this.GDIp.CreateBitmapFromFile(gifFile)
this.Frames := new this._FramesHandling(this.GDIp, this.pBitmap, UserFunc, cycle)
this.GDIp.GetImageDimensions(this.pBitmap, width, height)
this.width := width
this.height := height
}
Play() {
this.playing := true
this.Frames.PlayFrames()
}
Pause() {
if this.playing {
this.playing := false
timer := this.Frames._PlayTimer
SetTimer, % timer, Delete
}
}
Stop() {
this.Pause()
this.ShowFrame(1)
}
Prev() {
this.ShowFrame("prev")
}
Next() {
this.ShowFrame("next")
}
ShowFrame(which) { ; 'which' can be "prev", "next" or "", or 1-based frame index
this.Pause()
(which = "prev" && this.Frames.currentFrame -= 2)
(which + 0 && this.Frames.currentFrame := which - 1)
this.Frames.PlayFrames()
}
GetFrameByIndex(idx) {
Return hBitmap := this.Frames.GetFrame(idx - 1)
}
playing[] {
get {
Return this.Frames.playing
}
set {
Return this.Frames.playing := value
}
}
framesCount[] {
get {
Return this.Frames.frameCount
}
}
__Delete() {
this.Frames.Clear()
this.GDIp.DisposeImage(this.pBitmap)
this.Delete("Frames")
this.GDIp.Release()
}
class _FramesHandling {
__New(GDIp, pBitmap, userFunc, cycle) {
this.GDIp := GDIp
this.pBitmap := pBitmap
this.userFunc := userFunc
this.cycle := cycle
this.GetFrameCount()
this.GetFrameDelay()
this._PlayTimer := ObjBindMethod(this, "PlayFrames")
this._currentFrame := 1
}
currentFrame[] {
get {
Return this._currentFrame
}
set {
Return this._currentFrame := value < 1 ? this.frameCount + value : value > this.frameCount ? 1 : value
}
}
PlayFrames() {
Critical
frameIdx := ++this.currentFrame - 1
if ( this.playing && this.currentFrame != (this.cycle ? 0xFFFFFFFF : this.frameCount) ) {
timer := this._PlayTimer
SetTimer, % timer, % "-" this.frameDelay[frameIdx]
}
if userFunc := this.userFunc {
%userFunc%(this.currentFrame, this.GetFrame(frameIdx))
}
}
GetFrameCount() {
this.frameCount := this.GDIp.GetFrameCount(this.pBitmap, dimensionIDs, size)
this.SetCapacity("dimensionIDs", size)
this.pDimensionIDs := this.GetAddress("dimensionIDs")
DllCall("RtlMoveMemory", "Ptr", this.pDimensionIDs, "Ptr", &dimensionIDs, "Ptr", size)
VarSetCapacity(dimensionIDs, 0), dimensionIDs := ""
this.currentFrame := 0
}
GetFrameDelay() {
this.GDIp.GetPropertyItem(this.pBitmap, PropertyTagFrameDelay := 0x5100, item)
len := NumGet(item, 4, "UInt")
val := NumGet(item, 8 + A_PtrSize, "UPtr")
this.frameDelay := []
Loop, % len//4 {
i := A_Index - 1
n := NumGet(val + i*4, "UInt") * 10
this.frameDelay[i] := n ? n : 100
}
}
GetFrame(idx) {
this.GDIp.ImageSelectActiveFrame(this.pBitmap, this.pDimensionIDs, idx)
Return this.GDIp.CreateHBITMAPFromBitmap(this.pBitmap)
}
Clear() {
this.playing := false
timer := this._PlayTimer
SetTimer, % timer, Delete
this.Delete("dimensionIDs")
}
}
}
class GDIplus {
__New() {
static Instance := ""
if Instance.references {
++Instance.references
Return Instance
}
this.references := 1
if !DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
DllCall("LoadLibrary", "Str", "gdiplus")
VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
DllCall("gdiplus\GdiplusStartup", "UPtrP", pToken, "Ptr", &si, "Ptr", 0)
this.token := pToken
Return Instance := this
}
Release() {
if --this.references
Return
DllCall("gdiplus\GdiplusShutdown", "Ptr", this.token)
if hModule := DllCall("GetModuleHandle", "Str", "gdiplus", "Ptr")
DllCall("FreeLibrary", "Ptr", hModule)
}
CreateBitmapFromFile(sFile) {
DllCall("gdiplus\GdipCreateBitmapFromFile", "WStr", sFile, "PtrP", pBitmap)
Return pBitmap
}
CreateHBITMAPFromBitmap(pBitmap, Background=0xffffffff) {
DllCall("gdiplus\GdipCreateHBITMAPFromBitmap", "Ptr", pBitmap, "PtrP", hbm, "Int", Background)
Return hbm
}
GetImageDimensions(pBitmap, ByRef Width, ByRef Height) {
DllCall("gdiplus\GdipGetImageWidth", "Ptr", pBitmap, "UIntP", Width)
DllCall("gdiplus\GdipGetImageHeight", "Ptr", pBitmap, "UIntP", Height)
}
GetFrameCount(pBitmap, ByRef dimensionIDs, ByRef size) {
DllCall("gdiplus\GdipImageGetFrameDimensionsCount", "Ptr", pBitmap, "UIntP", frameDimensions)
VarSetCapacity(dimensionIDs, size := 16*frameDimensions)
DllCall("gdiplus\GdipImageGetFrameDimensionsList", "Ptr", pBitmap, "Ptr", &dimensionIDs, "UInt", frameDimensions)
DllCall("gdiplus\GdipImageGetFrameCount", "Ptr", pBitmap, "Ptr", &dimensionIDs, "UIntP", count)
Return count
}
GetPropertyItem(pBitmap, tag, ByRef item) {
DllCall("gdiplus\GdipGetPropertyItemSize", "Ptr", pBitmap, "UInt", tag, "UIntP", size)
VarSetCapacity(item, size, 0)
DllCall("gdiplus\GdipGetPropertyItem", "Ptr", pBitmap, "UInt", tag, "UInt", size, "Ptr", &item)
Return size
}
ImageSelectActiveFrame(pBitmap, pDimensionIDs, idx) {
Return DllCall("gdiplus\GdipImageSelectActiveFrame", "Ptr", pBitmap, "Ptr", pDimensionIDs, "Int", idx)
}
DisposeImage(pBitmap) {
Return DllCall("gdiplus\GdipDisposeImage", "Ptr", pBitmap)
}
}
Code: Select all
UserFunc := Func("PlayGif").Bind(hwndGif1)
MyGif := new AnimateGif(gifFile, UserFunc, false)
numberOfFrames := MyGif.framesCount() ; i get the number of frames in hopes I can do something when the animation reaches that number
Gui, Show,, Animated gif
Return
Play:
guicontrol, disable, Playbtn ; disable is working
MyGif.Play()
Return
PlayGif(hPic, currentFrameIdx, hBitmap) {
global numberOfFrames
GuiControl,, % hPic, HBITMAP: %hBitmap%
if (currentFrameIdx = numberOfFrames) {
MsgBox done ; works
guicontrol, enable, Playbtn ; dont work
}
tooltip, % currentFrameIdx " - " numberOfFrames ; just testing to make sure the numbers are correct
}