ça fait longtemps. Je profite des vacances et ce temps humide pour me faire plaisir avec Purebasic. La version 6Beta3 est très prometeuse.
Du coup j'ai repris un vieux projet. Dont je vous partage une petite partie. J'avais déjà partagé avec vous en 2019 une version (Voir ici)
C'est vrai que je n'ai pas partagé avec vous chaque version. Il faudrait que je le fasse plus souvent.
Voici donc venir la 6ème version. Reste encore du boulot, mais ça permet déjà de tester.
Au programme des nouveautés
- Compatibilité avec les ecrans 4K (support du DPI)
- Gestion du cache amélioré.
- Support de plusieurs Gadgets
- Quelques optimisations
J'ai encore du nettoyage de code et quelques fonctionnalités a finir. Mais si vous voulez tester n'hesitez pas.
Si vous avez des suggestions d'amélioration ou des bugs n'hesitez pas.
Code : Tout sélectionner
; ********************************************************************
; Program: Thumbnails
; Description: add a Thumbnails to select image
; Version: 6Alpha1
; Author: Thyphoon
; Date: August, 2021
; License: Free, unrestricted, credit
; appreciated but not required.
; Note: Please share improvement !
; ********************************************************************
CompilerIf Not Defined(Core,#PB_Module)
DeclareModule Core
Structure FileData
FilePath.s
Selected.b
State.b ; 0 No Loaded ; 1 loaded; 2 Displayed
Image.i
Map MetaData.s()
EndStructure
EndDeclareModule
Module Core
EndModule
CompilerEndIf
DeclareModule ImgTools
Structure DefDisplayImage
X.l
Y.l
Width.l
Height.l
EndStructure
Enumeration
#Image_Style_Fit
#Image_Style_Fill
#Image_Style_Stretch
EndEnumeration
Declare ImageToContainer(*result.DefDisplayImage,Image,ContainerWidth.l,ContainerHeight.l,Style.l=#Image_Style_Fit)
EndDeclareModule
Module ImgTools
Procedure ImageToContainer(*result.DefDisplayImage,Image,ContainerWidth.l,ContainerHeight.l,Style.l=#Image_Style_Fit)
If IsImage(Image)
Protected ImgRatio.l
Protected ContRatio.l
Protected ContWidth.l,ContHeight.l
ImgRatio.l = ImageWidth(Image) / ImageHeight(Image)
ContRatio.l = ContainerWidth /ContainerHeight
Select Style
Case #Image_Style_Fit
If ImgRatio<ContRatio
*result\Width=ImageWidth(Image)*ContainerHeight/ImageHeight(Image)
*result\Height=ContainerHeight
*result\X=(ContainerWidth-*result\Width)/2
*result\Y=0
Else
*result\Width=ContainerWidth
*result\Height=ImageHeight(Image)*ContainerWidth/ImageWidth(Image)
*result\X=0
*result\Y=(ContainerHeight-*result\Height)/2
EndIf
Case #Image_Style_Fill
If ImgRatio<ContRatio
*result\Width=ImageWidth(Image)*ContainerHeight/ImageHeight(Image)
*result\Height=ContainerHeight
*result\X=(ContainerWidth-*result\Width)/2
*result\Y=0
Else
*result\Width=ContainerWidth
*result\Height=ImageHeight(Image)*ContainerWidth/ImageWidth(Image)
*result\X=0
*result\Y=(ContainerHeight-*result\Height)/2
EndIf
Case #Image_Style_Stretch
*result\X=0
*result\Y=0
*result\Width=ContainerWidth
*result\Height=ContainerHeight
EndSelect
EndIf
EndProcedure
EndModule
;-Cache Module
DeclareModule Cache
EnableExplicit
Prototype.i CallBackLoadMedia(*Ptr.Core::FileData)
Structure Param
CallBackLoadMedia.CallBackLoadMedia
;LoadList
LoadListSemaphore.i
LoadListMutex.i
List LoadList.i()
;CacheList
CacheListMutex.i
Map CacheList.Core::FileData()
BackGroundThread.i
EndStructure
Global Param.Param
Param\LoadListSemaphore=CreateSemaphore(1)
Param\LoadListMutex=CreateMutex()
Param\CacheListMutex=CreateMutex()
Declare SetCallBackLoadMedia(CallBackLoadMedia.i)
Declare AddFileToLoadList(FilePath.s)
Declare CacheClean()
Declare AutoLoadStart()
Declare.i GetFileDataFromCache(FilePath.s)
Declare Quit()
EndDeclareModule
Module Cache
Procedure SetCallBackLoadMedia(CallBackLoadMedia.i)
Param\CallBackLoadMedia=CallBackLoadMedia
EndProcedure
Procedure AddFileToLoadList(FilePath.s)
Protected *Ptr
LockMutex(param\CacheListMutex)
*Ptr=AddMapElement(param\CacheList(),FilePath)
param\CacheList()\FilePath=FilePath
param\CacheList()\State=0
UnlockMutex(param\CacheListMutex)
LockMutex(Param\LoadListMutex)
AddElement(param\LoadList())
param\LoadList()=*Ptr
UnlockMutex(Param\LoadListMutex)
EndProcedure
Procedure LoadCacheDataThread(*Ptr.core::FileData)
If *Ptr\Image=0
Debug "Cache Load:"+*Ptr\FilePath
;Param\CallBackLoadMedia=0 ;To Force to use Internal Loader
If Param\CallBackLoadMedia<>0 ; <- Use extern procedure to Load Image
Debug "CallBackLoadMedia"
Param\CallBackLoadMedia(*Ptr)
Else
LockMutex(Param\CacheListMutex) ; <- Or intern with PB Plugin
*Ptr\Image=LoadImage(#PB_Any,*Ptr\FilePath)
UnlockMutex(Param\CacheListMutex)
EndIf
;Resize Image to Thumnails MaxSize
If *Ptr\Image<>0
Protected result.ImgTools::DefDisplayImage
ImgTools::ImageToContainer(@result,*Ptr\Image,256,256,ImgTools::#Image_Style_Fit)
ResizeImage(*Ptr\Image,result\Width,result\Height,#PB_Image_Smooth)
*Ptr\State=1; Ready to Display Image
;If can't load image
Else
;MessageRequester("Thumbnails Error","ERROR THREAD LOAD IMAGE"+Chr(13)+FilePath+Chr(13)+" in "+#PB_Compiler_Procedure+"()",#PB_MessageRequester_Ok | #PB_MessageRequester_Error)
Debug "ERROR THREAD LOAD IMAGE"+Chr(13)+*Ptr\FilePath
*Ptr\Image=CreateImage(#PB_Any,320,200)
StartDrawing(ImageOutput(*Ptr\Image))
Box(0,0,320,200,RGB(0,255,0))
StopDrawing()
*Ptr\State=1
EndIf
EndIf
SignalSemaphore(Param\LoadListSemaphore)
EndProcedure
Procedure BackgroundThread(n.l)
;Repeat
Debug "Run CacheBackgroundThread()****************"
Repeat
;If TrySemaphore(Param\LoadListSemaphore)
LockMutex(Param\LoadListMutex)
;Select Data from Id
If FirstElement(Param\LoadList())<>0
If CreateThread(@LoadCacheDataThread(),Param\LoadList())<>0
DeleteElement(Param\LoadList())
Else
Debug "Can't Start Thread"
End
EndIf
EndIf
UnlockMutex(Param\LoadListMutex)
;Else
; Debug "Wait Semaphore"
; EndIf
Delay(200)
Debug "LOADLIST SIZE:"+Str(ListSize(Param\LoadList()))
Until ListSize(Param\LoadList())=0
Delay(1000)
Debug "Finish CacheBackgroundThread()**************"
;ForEver
EndProcedure
Procedure Quit()
If IsThread(Param\BackGroundThread)
KillThread(Param\BackGroundThread)
EndIf
EndProcedure
Procedure AutoLoadStart()
If IsThread(Param\BackGroundThread)=#False
Param\BackGroundThread=CreateThread(@BackgroundThread(),0)
EndIf
EndProcedure
Procedure Free(*Ptr.core::FileData)
LockMutex(Param\CacheListMutex)
If IsImage(*Ptr\Image):FreeImage(*Ptr\Image):EndIf
FreeMap(*Ptr\MetaData())
UnlockMutex(Param\CacheListMutex)
EndProcedure
;TODO remake it
Procedure CacheClean()
Protected *Ptr.core::FileData
LockMutex(Param\CacheListMutex)
ForEach Param\CacheList()
If MapSize(Param\CacheList())<500
Break;
Else
*Ptr=Param\CacheList()
If *Ptr\State=1 And *Ptr\Selected=#False
Debug "Free Cache :"+GetFilePart(*Ptr\FilePath)+" State:"+Str(*Ptr\State)
Free(*Ptr)
DeleteMapElement(Param\CacheList())
EndIf
EndIf
Next
UnlockMutex(Param\CacheListMutex)
EndProcedure
Procedure.i GetFileDataFromCache(FilePath.s)
LockMutex(Param\CacheListMutex)
Protected *Ptr.core::FileData
*Ptr=FindMapElement(Param\CacheList(),FilePath)
UnlockMutex(Param\CacheListMutex)
If *Ptr=0
;AddToLoadList
LockMutex(Param\CacheListMutex)
*Ptr=AddMapElement(Param\CacheList(),FilePath)
*Ptr\FilePath=FilePath
*Ptr\State=0
*Ptr\Image=0
UnlockMutex(Param\CacheListMutex)
LockMutex(Param\LoadListMutex)
AddElement(param\LoadList())
Param\LoadList()=*Ptr
UnlockMutex(Param\LoadListMutex)
AutoLoadStart()
;Debug "Pas Trouve:"+GetFilePart(*Ptr\FilePath)
EndIf
;Debug "trouve:"+GetFilePart(*Ptr\FilePath)
ProcedureReturn *Ptr
EndProcedure
EndModule
;-Thumbs Module
DeclareModule Thumbs
EnableExplicit
;Declare SetBusyIcon(Image.i)
Declare SetCallBackLoadFromIndex(GadgetId.i,CallBackLoadFromIndex.i)
Declare SetCallBackSimpleClick(GadgetId.i,CallBackLoadFromIndex.i)
Declare SetCallBackDoubleClick(GadgetId.i,CallBackLoadFromIndex.i)
Declare ThumbnailsGadget(GadgetId.i,X.l,Y.l,Width.l,Height.l,Size.l)
Declare Start(GadgetId.i)
Declare Stop(GadgetId.i)
Declare AddImageToThumb(GadgetId.i,*Ptr)
Declare CheckEvent(Event.i)
;Declare Navigate
Declare NavigateGadget(GadgetId.i,X.l,Y.l,Width.l,Height.l,ThumbnailsId.i)
Declare DrawNavigate(Gadget.i)
Declare CheckEventNav(Event.i)
;-Declare List
Declare CallBackLoadFromInternalListIndex(GadgetId.i,Index.i,Lenght.l)
Declare AddFileToList(GadgetId.i,FilePath.s,nImage.i=0)
Declare ClearTheList(GadgetId.i)
Declare.i GetTheListSize(GadgetId.i)
EndDeclareModule
Module Thumbs
Prototype CallBackLoadFromIndex(GadgetId.i,Index.i,Lenght.l)
Prototype.i CallBackDoubleClick(GadgetId.i,CallBackLoadFromIndex.i)
Prototype.i CallBackSimpleClick(GadgetId.i,FileName.s,selected.b)
Structure gdt
BufferMutex.i
BufferImage.i
Gadget.i ;Canvas Gadget number
Size.l ;Thumb Size Width and Height
Index.i ;ThumbIndex
NbH.l ;Number of horizontal thumbnails
NbV.l ;Number of Vertical thumbnails
CursorStartY.l ; Cursor Y coord when clic
CursorPosY.l
CursorDeltaY.l ; Cursor Delta Y from StartY
ThumbsDeltaY.l ; Scroll Thumbs
CallBackLoadFromIndex.CallBackLoadFromIndex
CallBackDoubleClick.CallBackDoubleClick
CallBackSimpleClick.CallBackSimpleClick
FileListMutex.i
List FileList.core::FileData()
MutexThumb.i
List ThumbPointer.i()
;MutexRedraw.i
DrawBufferImage.b
GenerateBufferImage.b
LoadFromIndex.b
EndStructure
Structure GdtNav
ThumbnailsGadget.i
Gadget.i ;Canvas Gadget number
EndStructure
Structure param
BusyIcon.i
SetTimer.b
RefreshThread.i
GdtMutex.i
Map Gdt.Gdt()
Map GdtNav.GdtNav()
EndStructure
Global param.param
param\GdtMutex=CreateMutex()
param\SetTimer=#False
LoadFont(0, "Impact", 20, #PB_Font_Bold)
Procedure SetCallBackLoadFromIndex(GadgetId.i,CallBackLoadFromIndex.i)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
Param\Gdt()\CallBackLoadFromIndex=CallBackLoadFromIndex
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure SetCallBackDoubleClick(GadgetId.i,CallBackDoubleClick.i)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
Param\Gdt()\CallBackDoubleClick=CallBackDoubleClick
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure SetCallBackSimpleClick(GadgetId.i,CallBackSimpleClick.i)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
Param\Gdt()\CallBackSimpleClick=CallBackSimpleClick
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure ThumbnailsGadget(GadgetId.i,X.l,Y.l,Width.l,Height.l,Size.l)
Protected Gdt.i
Gdt=CanvasGadget(GadgetId.i,X.l,Y.l,Width.l,Height.l)
If GadgetId=#PB_Any
GadgetId=Gdt
EndIf
LockMutex(param\GdtMutex)
AddMapElement(Param\Gdt(),Str(GadgetId))
Param\Gdt()\BufferMutex=CreateMutex()
Param\Gdt()\FileListMutex=CreateMutex()
Param\Gdt()\Gadget=GadgetId
Param\Gdt()\Size=128
If param\SetTimer=#False
AddWindowTimer(GetActiveWindow(), 123, 75)
param\SetTimer=#True
EndIf
param\Gdt()\BufferMutex=CreateMutex()
param\Gdt()\MutexThumb=CreateMutex()
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure AddImageToThumb(GadgetId.i,*Ptr)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
LockMutex(param\Gdt()\MutexThumb)
AddElement(param\Gdt()\ThumbPointer())
param\Gdt()\ThumbPointer()=*Ptr
UnlockMutex(param\Gdt()\MutexThumb)
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure GenerateBufferImage(GadgetId.i)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
Protected.l _GadgetWidth=DesktopScaledX(GadgetWidth(Param\Gdt()\Gadget))
Protected.l _GadgetHeight=DesktopScaledY(GadgetHeight(Param\Gdt()\Gadget))
Protected.l _Size=DesktopScaledX(Param\Gdt()\Size)
Protected.l _ScrollWidth=DesktopScaledX(25)
Protected GdtWidth.l=_GadgetWidth-_ScrollWidth
Protected NbH.l=Int(GdtWidth/_Size):Param\Gdt()\NbH=NbH
Protected NbV.l=Int(_GadgetHeight/_Size):Param\Gdt()\NbV=NbV
Protected MarginH.l=(GdtWidth-NbH*_Size)/(NbH+1)
Protected MarginV.l=(_GadgetHeight-NbV*_Size)/(NbV+1)
;First Draw create the Image
LockMutex(param\Gdt()\BufferMutex)
If IsImage(param\Gdt()\BufferImage)=#False
param\Gdt()\BufferImage=CreateImage(#PB_Any,_GadgetWidth-_ScrollWidth,_GadgetHeight+2*_Size)
param\Gdt()\LoadFromIndex=#True
EndIf
UnlockMutex(param\Gdt()\BufferMutex)
LockMutex(param\Gdt()\MutexThumb)
Protected *Ptr.core::FileData
If param\Gdt()\CallBackLoadFromIndex>0
If param\Gdt()\LoadFromIndex=#True
param\Gdt()\LoadFromIndex=#False
ForEach Param\Gdt()\ThumbPointer()
*Ptr=Param\Gdt()\ThumbPointer()
If *Ptr>0
If *Ptr\State=2:*Ptr\State=1:EndIf
EndIf
DeleteElement(Param\Gdt()\ThumbPointer())
Next
;ClearList(Param\Gdt()\ThumbPointer()) ; ça plante donc au dessus j'efface au fur et a mesure avec DeleteElement(Param\Gdt()\ThumbPointer())
param\Gdt()\CallBackLoadFromIndex(Param\Gdt()\Gadget,Param\Gdt()\Index-Nbh,(NbV+2)*Nbh)
Debug "param\CallBackLoadFromIndex("+Str(Param\Gdt()\Index-Nbh)+","+Str((NbV+2)*Nbh)+")"
EndIf
Else
Debug "No Set CallBackLoadFromIndex"
EndIf
UnlockMutex(param\Gdt()\MutexThumb)
Protected ContinueGenerateBufferImage=#False
param\Gdt()\GenerateBufferImage=#True
LockMutex(param\Gdt()\BufferMutex)
If IsImage(Param\Gdt()\BufferImage) And StartVectorDrawing(ImageVectorOutput(Param\Gdt()\BufferImage))
VectorSourceColor(RGBA(128, 128, 128, 255))
FillVectorOutput()
Protected.l nx,ny,x,y,i
For ny=-1 To NbV+1
For nx=0 To NbH-1
;Position
x=nx*_Size+MarginH*nx+(MarginH)
y=ny*_Size+MarginV*ny+(MarginV)
i=nx+ny*NbH
;If in Limit
If i>-1 And i<ListSize(Param\Gdt()\ThumbPointer())
Protected State.b
Protected Image.i
Protected FileName.s
Protected Selected.b
LockMutex(param\Gdt()\MutexThumb)
*Ptr=0
If SelectElement(Param\Gdt()\ThumbPointer(),i)
*Ptr=Param\Gdt()\ThumbPointer()
Selected=0
State=0
Image=-1
FileName="No File"
If *Ptr>0
State=*Ptr\State
Image.i=*Ptr\Image
Selected=*Ptr\Selected
FileName.s=GetFilePart(*Ptr\FilePath)
EndIf
EndIf
UnlockMutex(param\Gdt()\MutexThumb)
If *Ptr>0
If State>0 And IsImage(Image) ;If Image loaded
Protected result.ImgTools::DefDisplayImage
ImgTools::ImageToContainer(@result,Image,_Size,_Size,ImgTools::#Image_Style_Fit)
;If element selected display green
Protected _Border.l,_BorderX2.l
;Draw Green Border when selected
If Selected=1
AddPathBox(result\X+x, result\Y+y,result\Width,result\Height)
VectorSourceColor(RGBA(0, 255, 0, 255))
FillPath()
_Border=DesktopScaledX(2)
_BorderX2=_Border*2
Else
_Border=DesktopScaledX(0)
_BorderX2=0
EndIf
;Draw Image
MovePathCursor(result\X+x+_Border,result\Y+y+_Border)
DrawVectorImage(ImageID(Image),255,result\Width-_BorderX2,result\Height-_BorderX2)
LockMutex(param\Gdt()\MutexThumb)
*Ptr\State=2
UnlockMutex(param\Gdt()\MutexThumb)
Else
AddPathBox(x, y, _Size,_Size)
VectorSourceColor(RGBA(0, 0, 0, 255))
FillPath()
VectorFont(FontID(0), 30)
VectorSourceColor(RGBA(0, 125, 0, 255))
MovePathCursor(result\X+x+_Border,result\Y+y+_Border+10)
DrawVectorText("Wait....")
ContinueGenerateBufferImage=#True
EndIf
VectorFont(FontID(0), 40)
MovePathCursor(x+(_Size-VectorTextWidth(FileName))/2,y+result\Height-VectorTextHeight(FileName))
VectorSourceColor(RGBA(255, 255, 255, 255))
DrawVectorText(Str(*Ptr\Selected)+FileName)
EndIf
Else ;overLimit
AddPathBox(x, y, _Size,_Size)
VectorSourceColor(RGBA(255, 0, 0, 255))
FillPath()
EndIf
Next
Next
MovePathCursor(10,500)
VectorFont(FontID(0), 40)
VectorSourceColor(RGBA(255, 255, 255, 255))
DrawVectorText("Test")
StopVectorDrawing()
EndIf
If ContinueGenerateBufferImage=#False
param\Gdt()\GenerateBufferImage=#False
Debug"END REDRAW ALL IS DISPLAY"
Else
Cache::AutoLoadStart()
EndIf
param\Gdt()\DrawBufferImage=#True
UnlockMutex(param\Gdt()\BufferMutex)
;Cache::CacheClean()
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure Refresh(time.l)
Protected DeltaIndex.l
Repeat
LockMutex(param\GdtMutex)
ForEach param\Gdt()
Protected UpdateList.b=#False
Protected *Gdt.Gdt
*Gdt=param\Gdt()
Protected _Size=DesktopScaledX(*Gdt\Size)
;Scroll
If *Gdt\CursorStartY>0
If GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseY)<>0
*Gdt\CursorPosY=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseY)
EndIf
*Gdt\CursorDeltaY=*Gdt\CursorStartY-*Gdt\CursorPosY
*Gdt\ThumbsDeltaY=*Gdt\ThumbsDeltaY+(*Gdt\CursorDeltaY/10)
EndIf
;Change Index when Scroll > Thumbnails
If *Gdt\ThumbsDeltaY>_Size
DeltaIndex=Int(*Gdt\ThumbsDeltaY/_Size)* *Gdt\NbH
*Gdt\Index=*Gdt\Index-DeltaIndex
*Gdt\ThumbsDeltaY=*Gdt\ThumbsDeltaY%_Size
UpdateList=#True
EndIf
If *Gdt\ThumbsDeltaY<-_Size
DeltaIndex=Abs(Int(*Gdt\ThumbsDeltaY/_Size)* *Gdt\NbH)
*Gdt\Index=*Gdt\Index+DeltaIndex
*Gdt\ThumbsDeltaY=*Gdt\ThumbsDeltaY%_Size
UpdateList=#True
EndIf
;Limit Up Scroll
If *Gdt\Index<=0 And *Gdt\ThumbsDeltaY>0
*Gdt\Index=0
*Gdt\ThumbsDeltaY=0
Debug "Limit Up Scroll"
EndIf
;Limit Down Scroll
;If *Gdt\Index>
;EndIf
If UpdateList=#True
*Gdt\LoadFromIndex=#True
*Gdt\GenerateBufferImage=#True
*Gdt\DrawBufferImage=#True
EndIf
If *Gdt\GenerateBufferImage=#True
GenerateBufferImage(*Gdt\Gadget)
EndIf
Protected.l _GadgetHeight=DesktopScaledX(GadgetHeight(*Gdt\Gadget))
Protected.l _ScrollWidth=DesktopScaledX(25)
Protected.l _ScrollHeight=_ScrollWidth*2
If *Gdt\DrawBufferImage=#True
If StartVectorDrawing(CanvasVectorOutput(*Gdt\Gadget))
LockMutex(*Gdt\BufferMutex)
If IsImage(*Gdt\BufferImage)
MovePathCursor(0,*Gdt\ThumbsDeltaY-_Size)
DrawVectorImage(ImageID(*Gdt\BufferImage))
AddPathBox(ImageWidth(*Gdt\BufferImage),0,_ScrollWidth,_GadgetHeight):VectorSourceColor(RGBA(100, 100, 100, 255)):FillPath()
AddPathBox(ImageWidth(*Gdt\BufferImage),_GadgetHeight/2-_ScrollHeight-*Gdt\CursorDeltaY,_ScrollWidth,_ScrollHeight):VectorSourceColor(RGBA(200, 200, 200, 255)):FillPath()
Else
Debug "can't draw BufferImage"
EndIf
UnlockMutex(*Gdt\BufferMutex)
StopVectorDrawing()
*Gdt\DrawBufferImage=#False
EndIf
EndIf
UnlockMutex(param\GdtMutex)
; If *Gdt\DrawBufferImage=#True
; Delay(75)
; Else
; Delay(200)
; EndIf
Next
Delay(75)
ForEver
EndProcedure
Procedure MyEvent()
Protected *Gdt.Gdt
LockMutex(Param\GdtMutex)
*Gdt=FindMapElement(Param\Gdt(), Str(EventGadget()))
If *Gdt<>0
UnlockMutex(Param\GdtMutex)
Protected.l _GadgetWidth=DesktopScaledX(GadgetWidth(*Gdt\Gadget))
Protected.l _GadgetHeight=DesktopScaledY(GadgetHeight(*Gdt\Gadget))
Protected.l _Size=DesktopScaledX(*Gdt\Size)
Protected.l _ScrollWidth=DesktopScaledX(25)
;Scroll Event
If GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseX)>_GadgetWidth-_ScrollWidth
;Start Scroll
If EventType()=#PB_EventType_LeftButtonDown
If *Gdt\CursorStartY=0
*Gdt\CursorStartY=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseY)
*Gdt\CursorPosY=*Gdt\CursorStartY
Debug "Start Scroll"
EndIf
EndIf
EndIf
;Scroll is Enable
If *Gdt\CursorStartY>0
*Gdt\DrawBufferImage=#True
If EventType()=#PB_EventType_MouseMove
*Gdt\CursorPosY=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseY)
EndIf
;Stop Scroll
If EventType() = #PB_EventType_LeftButtonUp
*Gdt\CursorStartY=0
*Gdt\CursorDeltaY=0
Debug "Stop Scroll"
EndIf
;Thumbnails Event
ElseIf GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseX)<_GadgetWidth-_ScrollWidth
;Change Thumbs Size with MouseWheel
If EventType() = #PB_EventType_MouseWheel
*Gdt\Size=*Gdt\Size+GetGadgetAttribute(*Gdt\Gadget,#PB_Canvas_WheelDelta)*8
*Gdt\LoadFromIndex=#True
*Gdt\GenerateBufferImage=#True
;param\DrawBufferImage=#True
EndIf
;Select Media
If EventType()=#PB_EventType_LeftClick Or EventType()=#PB_EventType_LeftDoubleClick
Protected GdtWidth.l=_GadgetWidth-_ScrollWidth
Protected NbH.l=Int(GdtWidth/_Size):*Gdt\NbH=NbH
Protected NbV.l=Int(_GadgetHeight/_Size):*Gdt\NbV=NbV
Protected MarginH.l=(GdtWidth-NbH* _Size)/(NbH+1)
Protected MarginV.l=(_GadgetHeight-NbV* _Size)/(NbV+1)
Protected x.l=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseX)
Protected y.l=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseY)
Protected nx.l=(x-MarginH)/(_Size+MarginH)
Protected ny.l=(y-MarginV-*Gdt\ThumbsDeltaY)/(_Size+MarginV)
Debug Str(x)+","+Str(y)
Protected index.l=nx+ny*NbH+NbH
Debug "INDEX Selected:"+Str(index)
Protected *Ptr.core::FileData
LockMutex(*Gdt\MutexThumb)
;Get
If index>-1
If SelectElement(*Gdt\ThumbPointer(),index)
*Ptr=*Gdt\ThumbPointer()
If *Ptr<>0
Select EventType()
Case #PB_EventType_LeftClick
Debug GetFilePart(*Ptr\FilePath)+" Selected:"+Str(*Ptr\Selected)
*Ptr\Selected=1-*Ptr\Selected
Debug "Left CLick"
; Debug Param\CallBackSimpleClick
; If Param\CallBackSimpleClick<>0 ; check if a @Procedure is added
; Debug "@procedure"
; Param\CallBackSimpleClick(Param\FileList()\FileName,Param\FileList()\Selected)
; EndIf
Case #PB_EventType_LeftDoubleClick
; Debug "Left Double Click"
; If Param\CallBackDoubleClick<>0 ; check if a @Procedure is added
; Debug "@procedure"
; Param\CallBackDoubleClick(Param\FileList()\FileName)
; EndIf
; Param\IndexNav=index
EndSelect
EndIf
EndIf
EndIf
UnlockMutex(*Gdt\MutexThumb)
*Gdt\DrawBufferImage=#True
*Gdt\GenerateBufferImage=#True
EndIf
EndIf
EndIf
UnlockMutex(Param\GdtMutex)
EndProcedure
Procedure Start(GadgetId.i)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
If IsThread(Param\RefreshThread)=#False
Param\RefreshThread=CreateThread(@Refresh(),10)
EndIf
param\Gdt()\LoadFromIndex=#True
param\Gdt()\GenerateBufferImage=#True
param\Gdt()\DrawBufferImage=#True
BindGadgetEvent(GadgetId,@MyEvent(),#PB_All)
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure Stop(GadgetId.i)
LockMutex(param\GdtMutex)
UnbindGadgetEvent(GadgetId,@MyEvent(),#PB_All)
If FindMapElement(Param\Gdt(), Str(GadgetId))
If IsThread(Param\RefreshThread)=#True
KillThread(Param\RefreshThread)
EndIf
param\Gdt()\LoadFromIndex=#False
param\Gdt()\GenerateBufferImage=#False
param\Gdt()\DrawBufferImage=#False
Cache::Quit()
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure CheckEvent(Event.i)
Protected *Gdt.Gdt
LockMutex(Param\GdtMutex)
Debug "CheckEvent:"+Str(EventGadget())
*Gdt=FindMapElement(Param\Gdt(), Str(EventGadget()))
If *Gdt<>0
Debug Param\Gdt()
;*Gdt=Param\Gdt()
UnlockMutex(Param\GdtMutex)
If Event=#PB_Event_Timer
;DrawThumbnails()
EndIf
Select Event
Case #PB_Event_Gadget
If EventType()=#PB_EventType_Focus
Debug "Focus"
EndIf
If EventType()=#PB_EventType_LostFocus
Debug "lost Focus"
EndIf
;Scroll Event
If GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseX)>GadgetWidth(*Gdt\Gadget)-25
;Start Scroll
If EventType()=#PB_EventType_LeftButtonDown
If *Gdt\CursorStartY=0
*Gdt\CursorStartY=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseY)
*Gdt\CursorPosY=*Gdt\CursorStartY
Debug "Start Scroll"
EndIf
EndIf
EndIf
;Scroll is Enable
If *Gdt\CursorStartY>0
*Gdt\DrawBufferImage=#True
If EventType()=#PB_EventType_MouseMove
*Gdt\CursorPosY=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseY)
EndIf
;Stop Scroll
If EventType() = #PB_EventType_LeftButtonUp
*Gdt\CursorStartY=0
*Gdt\CursorDeltaY=0
Debug "Stop Scroll"
EndIf
;Thumbnails Event
ElseIf GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseX)<GadgetWidth(*Gdt\Gadget)-25
;Change Thumbs Size with MouseWheel
If EventType() = #PB_EventType_MouseWheel
*Gdt\Size=Param\Gdt()\Size+GetGadgetAttribute(*Gdt\Gadget,#PB_Canvas_WheelDelta)*8
*Gdt\LoadFromIndex=#True
*Gdt\GenerateBufferImage=#True
;param\DrawBufferImage=#True
EndIf
;Select Media
If EventType()=#PB_EventType_LeftClick Or EventType()=#PB_EventType_LeftDoubleClick
Protected GdtWidth.l=GadgetWidth(*Gdt\Gadget)-25
Protected NbH.l=Int(GdtWidth/*Gdt\Size):*Gdt\NbH=NbH
Protected NbV.l=Int(GadgetHeight(*Gdt\Gadget)/*Gdt\Size):*Gdt\NbV=NbV
Protected MarginH.l=(GdtWidth-NbH* *Gdt\Size)/(NbH+1)
Protected MarginV.l=(GadgetHeight(*Gdt\Gadget)-NbV* *Gdt\Size)/(NbV+1)
Protected x.l=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseX)
Protected y.l=GetGadgetAttribute(*Gdt\Gadget, #PB_Canvas_MouseY)
Protected nx.l=(x-MarginH)/(*Gdt\Size+MarginH)
Protected ny.l=(y-MarginV-*Gdt\ThumbsDeltaY)/(*Gdt\Size+MarginV)
Debug Str(nx)+","+Str(ny)
Protected index.l=nx+ny*NbH+NbH
Debug "INDEX Selected:"+Str(index)
Protected *Ptr.core::FileData
LockMutex(*Gdt\MutexThumb)
;Get
If index>-1 And SelectElement(*Gdt\ThumbPointer(),index)<>0
*Ptr=*Gdt\ThumbPointer()
Debug"ATTENTION"
Debug *Ptr
Select EventType()
Case #PB_EventType_LeftClick
;*Ptr\Selected=1
*Ptr\Selected=1-*Ptr\Selected
Debug "Left CLick"
; Debug Param\CallBackSimpleClick
; If Param\CallBackSimpleClick<>0 ; check if a @Procedure is added
; Debug "@procedure"
; Param\CallBackSimpleClick(Param\FileList()\FileName,Param\FileList()\Selected)
; EndIf
Case #PB_EventType_LeftDoubleClick
; Debug "Left Double Click"
; If Param\CallBackDoubleClick<>0 ; check if a @Procedure is added
; Debug "@procedure"
; Param\CallBackDoubleClick(Param\FileList()\FileName)
; EndIf
; Param\IndexNav=index
EndSelect
EndIf
UnlockMutex(*Gdt\MutexThumb)
*Gdt\DrawBufferImage=#True
*Gdt\GenerateBufferImage=#True
EndIf
EndIf
EndSelect
EndIf
UnlockMutex(Param\GdtMutex)
EndProcedure
Procedure CallBackLoadFromInternalListIndex(GadgetId.i,Index.i,Lenght.l)
Protected n.l
Protected TmpIndex.i
LockMutex(Param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
Debug "CallBackLoadFromIndex("+Str(Index)+","+Str(Lenght)+")"
For n=1 To Lenght
TmpIndex=Index+n-1
If TmpIndex>=0 And TmpIndex<ListSize(Param\Gdt()\FileList())
SelectElement(Param\Gdt()\FileList(),TmpIndex)
Protected *Ptr.Core::FileData
*Ptr=Cache::GetFileDataFromCache(Param\Gdt()\FileList()\FilePath)
If *Ptr
Thumbs::AddImageToThumb(GadgetId,*Ptr)
Else
Thumbs::AddImageToThumb(GadgetId,0)
EndIf
Else
Thumbs::AddImageToThumb(GadgetId,-1)
EndIf
Next
EndIf
UnlockMutex(Param\GdtMutex)
EndProcedure
;-Navigate
Procedure NavigateGadget(GadgetId.i,X.l,Y.l,Width.l,Height.l,ThumbnailsId.i)
Protected Gdt.i
Gdt=CanvasGadget(GadgetId.i,X.l,Y.l,Width.l,Height.l)
If GadgetId=#PB_Any
GadgetId=Gdt
EndIf
If AddMapElement(Param\GdtNav(),Str(GadgetId),#PB_Map_ElementCheck)
Param\GdtNav()\Gadget=GadgetId
Param\GdtNav()\ThumbnailsGadget=ThumbnailsId
EndIf
EndProcedure
Procedure DrawNavigate(Gadget.i)
; Protected FileName.s
; StartVectorDrawing(CanvasVectorOutput(Gadget))
; VectorSourceColor(GetWindowColor(0))
; FillVectorOutput()
; Protected h.l=GadgetWidth(Gadget)
; If FindMapElement(Param\Navigate(),Str(Gadget))
; If FindMapElement(Param\Thumbnails(),Str(Param\Navigate()\ThumbnailsGadget))
; h=GadgetHeight(Param\Navigate()\Gadget)
; index=Param\Thumbnails()\IndexNav
; nb=(Int(GadgetWidth(Param\Navigate()\Gadget)/h)-2)/2
;
;
; For z=1 To nb
; ;Right
;
; LockMutex(Param\FileListMutex)
;
; index_Right.i=index+z
; FileName_Right.s=""
; image_left.i=-1
; If index_Right>=0 And index_Right<ListSize(Param\FileList())
; If SelectElement(Param\FileList(),index_Right)>0
; FileName_Right.s=Param\FileList()\FileName
; EndIf
; EndIf
;
; ;Left
; index_Left.i=index-z
; FileName_Left.s=""
; image_left.i=-1
; If index_Left>=0 And index_Left<ListSize(Param\FileList())
;
; If SelectElement(Param\FileList(),index_Left)>0
; FileName_Left.s=Param\FileList()\FileName
; EndIf
; EndIf
; UnlockMutex(Param\FileListMutex)
;
;
; If FileName_Right<>""
; image_right.i=GetImageByName(FileName_Right)
; x=(GadgetWidth(Param\Navigate()\Gadget)/2-h/2)+z*h
; y=0
; AddPathBox(x,y,h,h)
; SaveVectorState()
; ClipPath()
; DrawNavThumb(image_right,x,y,255-(z*200/nb));
; RestoreVectorState()
; EndIf
;
; If FileName_Left<>""
; image_left.i=GetImageByName(FileName_Left.s)
; x=(GadgetWidth(Param\Navigate()\Gadget)/2-GadgetHeight(Param\Navigate()\Gadget)/2)-z*GadgetHeight(Param\Navigate()\Gadget)
; y=0
; AddPathBox(x,y,GadgetHeight(Param\Navigate()\Gadget),GadgetHeight(Param\Navigate()\Gadget))
; SaveVectorState()
; ClipPath()
; DrawNavThumb(image_left,x,y,255-(z*200/nb));-(z*200/nb)
; RestoreVectorState()
; EndIf
;
;
; Next
;
; If index>=0 And index<ListSize(Param\FileList())
; FileName.s=""
; If SelectElement(Param\FileList(),index)>0
; FileName.s=Param\FileList()\FileName
; EndIf
; EndIf
;
;
; If FileName<>""
; image=GetImageByName(FileName.s)
; x=GadgetWidth(Param\Navigate()\Gadget)/2-GadgetHeight(Param\Navigate()\Gadget)/2
; y=0
; AddPathBox(x,y,GadgetHeight(Param\Navigate()\Gadget),GadgetHeight(Param\Navigate()\Gadget))
; SaveVectorState()
; ClipPath()
; DrawNavThumb(image,x,y,255)
; RestoreVectorState()
; AddPathBox(x,y,GadgetHeight(Param\Navigate()\Gadget),GadgetHeight(Param\Navigate()\Gadget))
; VectorSourceColor(RGBA(255, 0, 0, 255))
; StrokePath(2)
; EndIf
;
;
; EndIf
; EndIf
; StopVectorDrawing()
EndProcedure
Procedure CheckEventNav(Event.i)
; If Event=#PB_Event_Timer
; ForEach Param\Navigate()
; If Param\Refresh=#True
; DrawNavigate(Param\Navigate()\Gadget)
; EndIf
; Next
; If Param\Refresh=#False
; EndIf
; EndIf
;
; ForEach Param\Navigate()
;
; If Event = #PB_Event_Gadget And EventGadget() = Param\Navigate()\Gadget
;
; If EventType()=#PB_EventType_Focus
; Debug "Focus"
; EndIf
;
; If EventType()=#PB_EventType_LostFocus
; Debug "lost Focus"
; EndIf
;
; If EventType()=#PB_EventType_LeftButtonDown
; If GetGadgetAttribute(Param\Navigate()\Gadget, #PB_Canvas_MouseX)>GadgetWidth(Param\Navigate()\Gadget)/2
; param\Thumbnails(Str(Param\Navigate()\ThumbnailsGadget))\IndexNav+1
; Else
; param\Thumbnails(Str(Param\Navigate()\ThumbnailsGadget))\IndexNav-1
; EndIf
;
; LockMutex(Param\FileListMutex)
; If param\Thumbnails()\IndexNav<0:param\Thumbnails()\IndexNav=0:EndIf
; If param\Thumbnails()\IndexNav>ListSize(Param\FileList())-1:param\Thumbnails()\IndexNav=ListSize(Param\FileList())-1:EndIf
;
; index=param\Thumbnails()\IndexNav
;
; If index>-1 And SelectElement(Param\FileList(),index)<>0
; If Param\Thumbnails()\CallBackDoubleClick<>0 ; check if a @Procedure is added
; Param\Thumbnails()\CallBackDoubleClick(Param\FileList()\FileName)
; EndIf
; EndIf
; UnlockMutex(Param\FileListMutex)
; EndIf
; EndIf
; Next
EndProcedure
;-List
Procedure AddFileToList(GadgetId.i,FilePath.s,nImage.i=0)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
;Select Data from Id
AddElement(Param\Gdt()\FileList())
Param\Gdt()\FileList()\FilePath=FilePath
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure ClearTheList(GadgetId.i)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
ClearList(Param\Gdt()\FileList())
EndIf
UnlockMutex(param\GdtMutex)
EndProcedure
Procedure.i GetTheListSize(GadgetId.i)
LockMutex(param\GdtMutex)
If FindMapElement(Param\Gdt(), Str(GadgetId))
Protected n.i
LockMutex(Param\Gdt()\FileListMutex)
n=ListSize(Param\Gdt()\FileList())
UnlockMutex(Param\Gdt()\FileListMutex)
EndIf
UnlockMutex(param\GdtMutex)
ProcedureReturn n
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseMD5Fingerprint()
Enumeration
#Win_main
#Gdt_Nav
#Gdt_ThumbA
#Gdt_ThumbB
EndEnumeration
Procedure CallBackDoubleClick(FileName.s)
Debug FileName
EndProcedure
Global NewList CurrentList.s()
Procedure CallBackLoadFromIndex(GadgetId.i,Index.i,Lenght.l)
Protected n.l
Protected TmpIndex.i
Debug "CallBackLoadFromIndex("+Str(Index)+","+Str(Lenght)+")"
For n=1 To Lenght
TmpIndex=Index+n-1
If TmpIndex>=0 And TmpIndex<ListSize(CurrentList())
SelectElement(CurrentList(),TmpIndex)
Protected *Ptr.Core::FileData
*Ptr=Cache::GetFileDataFromCache(CurrentList())
If *Ptr
Thumbs::AddImageToThumb(GadgetId,*Ptr)
Else
Thumbs::AddImageToThumb(GadgetId,0)
EndIf
Else
Thumbs::AddImageToThumb(GadgetId,-1)
EndIf
Next
EndProcedure
If OpenWindow(#Win_main, 0, 0, 1024, 600, "Thumbnails", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
LoadFont(0, "Arial", 20, #PB_Font_Bold)
Thumbs::ThumbnailsGadget(#Gdt_ThumbA,0,50,512,550,128)
Thumbs::ThumbnailsGadget(#Gdt_ThumbB,512,50,512,550,128)
Define Repertoire$
Define Event.i
Repertoire$="D:\Photos\2019-07-14 Week-End Chez Angélique et Nadège\";"D:\Documents a Trier\Camera\";"C:\Users\413\Pictures\";"D:\Cloud\Amazon Drive\Photos\Photos a trier\"
Repertoire$=PathRequester("Chose Directory", Repertoire$)
If ExamineDirectory(0, Repertoire$, "*.jpg")
While NextDirectoryEntry(0)
If DirectoryEntryType(0) = #PB_DirectoryEntry_File
AddElement(CurrentList())
CurrentList()=Repertoire$+DirectoryEntryName(0)
Debug DirectoryEntryName(0)
EndIf
Wend
FinishDirectory(0)
EndIf
Thumbs::SetCallBackLoadFromIndex(#Gdt_ThumbA,@CallBackLoadFromIndex())
Thumbs::SetCallBackLoadFromIndex(#Gdt_ThumbB,@CallBackLoadFromIndex())
Thumbs::Start(#Gdt_ThumbA)
Thumbs::Start(#Gdt_ThumbB)
Repeat
Delay(1)
Event = WindowEvent()
;Thumbs::CheckEvent(Event.i)
;MagicGdt::EventThumb(Event)
;MagicGdt::EventNav(Event)
Until Event = #PB_Event_CloseWindow
Thumbs::Stop(#Gdt_ThumbA)
Thumbs::Stop(#Gdt_ThumbB)
EndIf
CompilerEndIf