'Load dialogue with image preview 'Jolly Roger June 2005 'Using code by Abel, Sean and Trondoc 'Updated by Brian Pugh, November 2016 'Updated by Brian Pugh, March 2023 autodefine "off" $include "windowssdk.inc" 'Global variable definitions & declaration for load dialogue WINDOW imagepreviewwindow INT openbutton,cancelbutton,listview,editbox,upbutton,foldernameeditbox DIALOG loaddialogue ISTRING directoryname[260],chosenfilename[260] UINT dir openbutton=1 cancelbutton=2 listview=3 editbox=4 upbutton=5 foldernameeditbox=6 'Standard NMLISTVIEW. When a column is clicked on Windows sends a variable of this type in @QUAL TYPE NMLISTVIEW INT hwndFrom INT idFrom INT code INT iItem INT iSubItem INT uNewState INT uOldState INT uChanged INT ptActionx INT ptActiony INT lParam ENDTYPE NMLISTVIEW lv 'Memory and variable to read data out of @QUAL MEMORY qualmem TYPE SHFILEINFO INT hIcon INT iIcon INT Attributes ISTRING DisplayName[260] ISTRING TypeName[79] ENDTYPE SHFILEINFO shfi TYPE LV_ITEM UINT mask INT iItem INT iSubItem UINT state UINT stateMask POINTER text INT cchTextMax INT iImage 'index of the listview items icon INT lParam '32-bit value to associate with item ENDTYPE LV_ITEM lvi WINDOW win INT handle ISTRING filepath[260] OPENWINDOW win,0,0,640,480,0,0,"Load Preview Dialogue",&mainwindowhandler 'Set up dialogue box setuploadfiledialogue(win,GETSTARTPATH) 'Show the dialogue box and get the chosen filename filepath=chosenfilepath() handle=LOADIMAGE(filepath,@IMGSCALABLE) SHOWIMAGE win,handle,@IMGSCALABLE,0,0 DELETEIMAGE handle,@IMGSCALABLE WAITUNTIL IsWindowClosed(win) END SUB mainwindowhandler(),INT SELECT @MESSAGE CASE @IDCREATE CENTERWINDOW win CASE @IDCLOSEWINDOW CLOSEWINDOW win ENDSELECT RETURN 0 ENDSUB 'SUBs for load dialogue SUB chosenfilepath(),STRING DOMODAL loaddialogue RETURN chosenfilename ENDSUB SUB setuploadfiledialogue(parentwindow:WINDOW,startpath:STRING) 'Create dialogue CREATEDIALOG loaddialogue,0,0,320,370,@CAPTION,parentwindow,"Load Image",&dialoguehandler CONTROL loaddialogue,@BUTTON,"Open",190,230,100,20,@TABSTOP,openbutton CONTROL loaddialogue,@BUTTON,"Cancel",190,270,100,20,@TABSTOP,cancelbutton CONTROL loaddialogue,@LISTVIEW,"",12,40,296,130,0x50000041|@LVSSMALLICON|@LVSSORTASCENDING|@BORDER,listview CONTROL loaddialogue,@EDIT,"",12,180,296,20,@TABSTOP,editbox CONTROL loaddialogue,@BUTTON,"Up",12,6,25,25,@TABSTOP,upbutton CONTROL loaddialogue,@EDIT,"",50,6,256,25,@TABSTOP|@CTEDITMULTI|@CTEDITAUTOH|@CTEDITLEFT,foldernameeditbox 'Start with specified path if possible dir=FINDOPEN(startpath+"\\*.*") IF dir directoryname=startpath FINDCLOSE dir ELSE 'Can't start with specified path. Start at root of drive directoryname=LEFT$(GETSTARTPATH,INSTR(GETSTARTPATH,"\\")) ENDIF ENDSUB SUB dialoguehandler(),INT INT posn FLOAT aspectratio ISTRING filename[260],foldername[260],fileextension[32] SELECT @MESSAGE CASE @IDINITDIALOG CENTERWINDOW loaddialogue 'Remove border from edit control ModifyExStyle loaddialogue,0,WS_EX_CLIENTEDGE,6 RedrawFrame loaddialogue,6 'Colour edit control SETCONTROLCOLOR loaddialogue,6,RGB(31,81,255),RGB(240,240,240) 'Set listview to use icons SetImageList() 'Add a listview column CONTROLCMD loaddialogue,listview,@LVINSERTCOLUMN,0,"" CONTROLCMD loaddialogue,listview,@LVSETCOLWIDTH,0,250 ENABLECONTROL loaddialogue,openbutton,0 updatefilelistview() 'Create window to hold preview image OPENWINDOW imagepreviewwindow,12,210,150,150,@NOCAPTION|@BORDER,loaddialogue,"",&imagepreviewwindowhandler IF INSTR(directoryname,"\\")=LEN(directoryname) 'Starting at root of drive SETCONTROLTEXT loaddialogue,foldernameeditbox,directoryname ELSE 'Not starting at root of drive. Find foldername FOR posn=LEN(directoryname)-1 TO 1 STEP -1 IF MID$(directoryname,posn,1)="\\" foldername=MID$(directoryname,posn+1) 'Remove trailing \ foldername=LEFT$(foldername,LEN(foldername)-1) SETCONTROLTEXT loaddialogue,foldernameeditbox,foldername posn=1 ENDIF NEXT posn ENDIF CASE @IDCONTROL IF @CONTROLID=openbutton chosenfilename=directoryname+GETCONTROLTEXT(loaddialogue,editbox) CLOSEDIALOG loaddialogue ENDIF IF @CONTROLID=cancelbutton CLOSEDIALOG loaddialogue ENDIF IF @CONTROLID=listview IF @NOTIFYCODE=@NMCLICK 'Click on listview.Find name of file/folder clicked on qualmem = @QUAL READMEM qualmem,1,lv CONTROLCMD(loaddialogue,listview,@LVGETTEXT,lv.iItem,0,filename) 'If is not a folder then display preview image dir=FINDOPEN(directoryname+filename+"\\*.*") IF dir=0 'Is a supported file type INT imagehandle,width,height SETCONTROLTEXT loaddialogue,4,filename fileextension=LCASE$(RIGHT$(filename,3)) 'Find aspect ratios of images so not distorted in preview window aspectratio=0 SELECT fileextension CASE "gif" aspectratio=gifaspectratio(directoryname+filename) CASE "bmp" imagehandle=LOADIMAGE (directoryname+filename,@IMGBITMAP) GETBITMAPSIZE(imagehandle,width,height) IF height>0 THEN aspectratio=FLT(width)/height DELETEIMAGE imagehandle,@IMGBITMAP DEFAULT aspectratio=jpegaspectratio(directoryname+filename) ENDSELECT 'Show preview of image in preview window imagehandle=LOADIMAGE(directoryname+filename,@IMGSCALABLE) RECT imagepreviewwindow,0,0,150,150,0xFFFFFF,0xFFFFFF IF aspectratio=0 'Couldn't find aspect ratio for image SHOWIMAGE imagepreviewwindow,imagehandle,@IMGSCALABLE,0,0,150,150 ELSE 'Scale image so not distorted IF aspectratio>1 SHOWIMAGE imagepreviewwindow,imagehandle,@IMGSCALABLE,0,(150-150/aspectratio)/2,150,150/aspectratio ELSE SHOWIMAGE imagepreviewwindow,imagehandle,@IMGSCALABLE,(150-150*aspectratio)/2,0,150*aspectratio,150 ENDIF ENDIF DELETEIMAGE imagehandle,@IMGSCALABLE ENABLECONTROL loaddialogue,openbutton,1 ELSE 'Item is a folder RECT imagepreviewwindow,0,0,150,150,0xFFFFFF,0xFFFFFF SETCONTROLTEXT loaddialogue,editbox,"" ENABLECONTROL loaddialogue,openbutton,0 FINDCLOSE dir ENDIF ENDIF IF @NOTIFYCODE=@NMDBLCLK 'Doubled clicked in the listview box.Find name of file/folder double clicked qualmem = @QUAL READmem qualmem,1,lv CONTROLCMD(loaddialogue,listview,@LVGETTEXT,lv.iItem,0,filename) dir=FINDOPEN (directoryname+filename+"\\*.*") IF dir 'Double clicked on a folder or drive foldername=filename directoryname=directoryname+foldername+"\\" SETCONTROLTEXT loaddialogue,foldernameeditbox,foldername updatefilelistview() 'Enable Up button ENABLECONTROL loaddialogue,upbutton,1 FINDCLOSE dir ELSE 'Double clicked on a supported file.Get filename and close dialogue chosenfilename=directoryname+filename CLOSEDIALOG loaddialogue ENDIF ENDIF ENDIF IF @CONTROLID=upbutton 'Move up a folder IF INSTR(directoryname,"\\")=LEN(directoryname) 'At root of drive finddrives() 'Disable up button ENABLECONTROL loaddialogue,upbutton,0 SETCONTROLTEXT loaddialogue,foldernameeditbox,"My Computer" ELSE 'Not at root of drive.Remove part of directory name after \ FOR posn=LEN(directoryname)-1 TO 1 STEP -1 IF MID$(directoryname,posn,1)="\\" directoryname=LEFT$(directoryname,posn) updatefilelistview() SETCONTROLTEXT loaddialogue,editbox,"" ENABLECONTROL loaddialogue,openbutton,0 RECT imagepreviewwindow,0,0,150,150,0xFFFFFF,0xFFFFFF:'Clear preview window posn=1 ENDIF NEXT posn 'Update foldername editbox IF INSTR(directoryname,"\\")=LEN(directoryname) 'At root of drive after gone up a level SETCONTROLTEXT loaddialogue,foldernameeditbox,directoryname ELSE 'Not at root of drive after gone up a level. Find folder name FOR posn=LEN(directoryname)-1 TO 1 STEP -1 IF MID$(directoryname,posn,1)="\\" foldername=MID$(directoryname,posn+1) 'Remove trailing \ foldername=LEFT$(foldername,LEN(foldername)-1) SETCONTROLTEXT loaddialogue,foldernameeditbox,foldername posn=1 ENDIF NEXT posn ENDIF ENDIF ENDIF ENDSELECT RETURN 0 ENDSUB SUB SetImageList() MEMORY mem UINT hListview,hSHImageList 'Get handle for listview control hListview=GETCONTROLHANDLE(loaddialogue,listview) 'Find handle for shell icon image list and assign it to the listview image list allocmem(mem,len(shfi),1) hSHImageList=SHGetFileInfo("",0,mem,len(shfi),0x4001) 'SYSICONINDEX,SMALLICON freemem mem SendMessage(hListview,0x1003,1,hSHImageList) 'LVM_SETIMAGELIST ENDSUB 'Subroutine to retrieve the Display Name and Icon index for the drive SUB GetFileInfo(drive:STRING) MEMORY mem ALLOCMEM(mem,len(shfi),1) SHGetFileInfo(drive,0,mem,len(shfi),0x0301) 'DISPLAYNAME,ICON,SMALLICON READMEM mem,1,shfi FREEMEM mem ENDSUB SUB AddListViewItem(hWnd as window,id as int,itemnum as int,text as string,imagenum as int) lvi.mask=0x01|0x02 lvi.iitem=itemnum lvi.isubitem=0 lvi.text=text lvi.cchTextMax=len(text) lvi.iImage=imagenum lvi.lParam=15 SendMessage hWnd,4103/*LVM_INSERTITEM*/,0,&lvi,listview endsub SUB imagepreviewwindowhandler(),INT RETURN 0 ENDSUB SUB updatefilelistview() INT numberofitemsinlistview,item UINT dir,dir2 STRING fileorfoldername,fileextension 'Empty listview CONTROLCMD loaddialogue,listview,@LVDELETEALL numberofitemsinlistview=0 dir = FINDOPEN(directoryname+"*.*") IF dir 'Find names of all files & folders in current directory DO fileorfoldername = FINDNEXT(dir) IF fileorfoldername<>"" IF LEFT$((RIGHT$(fileorfoldername,4)),1)="." 'Item has a three character file extension fileextension=LCASE$(RIGHT$(fileorfoldername,3)) IF (fileextension="jpg")|(fileextension="bmp")|(fileextension="gif") GetFileInfo(directoryname+fileorfoldername) AddListViewItem(loaddialogue,listview,numberofitemsinlistview,fileorfoldername,shfi.iIcon) numberofitemsinlistview=numberofitemsinlistview+1 ENDIF ELSE 'Item does not have three character file extension 'Use FINDOPEN to see if it is a folder dir2=FINDOPEN(directoryname+fileorfoldername+"\*.*") IF dir2 IF fileorfoldername<>"." 'This item is a folder.Add chr$(10) to start so will be at top of list GetFileInfo(directoryname+fileorfoldername) AddListViewItem(loaddialogue,listview,numberofitemsinlistview,chr$(10)+fileorfoldername,shfi.iIcon) numberofitemsinlistview=numberofitemsinlistview+1 FINDCLOSE dir2 ENDIF ENDIF ENDIF ENDIF UNTIL fileorfoldername="" FINDCLOSE dir 'Remove CHR$(10) from folder names FOR item=0 TO numberofitemsinlistview-1 CONTROLCMD(loaddialogue,listview,@LVGETTEXT,item,0,fileorfoldername) IF ASC(fileorfoldername)=10 fileorfoldername=MID$(fileorfoldername,2) CONTROLCMD(loaddialogue,listview,@LVSETTEXT,item,0,fileorfoldername) ELSE 'No more folders item=numberofitemsinlistview-1 ENDIF NEXT item ENDIF ENDSUB SUB finddrives() INT drive,driveavailable[26],numberofitems UINT dir STRING driveletter numberofitems=0 'Check all possible drives from a:/ to z:/ FOR drive=0 TO 25 driveavailable[drive]=0 driveletter=CHR$(drive+65) dir=FINDOPEN(driveletter+":\\*.*") IF dir 'Drive is available driveavailable[drive]=1 FINDCLOSE dir ENDIF NEXT drive 'Empty listview CONTROLCMD loaddialogue,listview,@LVDELETEALL 'Fill listview with available drives FOR drive=0 TO 25 IF driveavailable[drive] GetFileInfo(CHR$(drive+65)+":\\") AddListViewItem(loaddialogue,listview,numberofitems,CHR$(drive+65)+":",shfi.iIcon) numberofitems=numberofitems+1 ENDIF NEXT drive ENDSUB SUB gifaspectratio(filename$:STRING),FLOAT 'Adapted from code by Trondoc BFILE GifFile CHAR widthLO,widthHI,heightLO,heightHI INT width,height FLOAT aspectratio aspectratio=0 IF(OPENFILE(GifFile,filename$,"R")=0) 'Start reading file at seventh byte SEEK GifFile,6 READ(GifFile,widthLO) READ(GifFile,widthHI) READ(GifFile,heightLO) READ(GifFile,heightHI) width=256*(widthHI&255)+(widthLO&255) height=256*(heightHI&255)+(heightLO&255) CLOSEFILE GifFile IF height>1 THEN aspectratio=FLT(width)/height ENDIF RETURN aspectratio ENDSUB SUB jpegaspectratio(imagefilename$:STRING),FLOAT 'Adapted from code by Trondoc BFILE JpgFile INT JpgLength,segLen,FilePos,imageheight,imagewidth CHAR byte1,byte2,heightHI,heightLO,widthLO,widthHI,segLenHI,segLenLO FLOAT aspectratio CHAR C0,C2,D0,D9 C0=CHR$(192) C2=CHR$(194) D0=CHR$(0xD0) D9=CHR$(0xD9) imageheight=0 imagewidth=0 aspectratio=0 IF(OPENFILE(JpgFile,imagefilename$,"R") = 0) JpgLength=LEN(JpgFile) READ(JpgFile,byte1) READ(JpgFile,byte2) Do READ(JpgFile,byte1) READ(JpgFile,byte2) IF byte2=C0 | byte2=C2 'Found start of frame 'SKIP 3 BYTES (FRAME LENGTH[2] AND SAMPLE PRECISION[1]) FilePos=SEEK(JpgFile) SEEK JpgFile,(FilePos+3) READ(JpgFile,heightHI) READ(JpgFile,heightLO) READ(JpgFile,widthHI) READ(JpgFile,widthLO) imageheight=(256*(heightHI&255))+(heightLO&255) imagewidth=(256*(widthHI&255))+(widthLO&255) ELSE 'SoF0 (Start of Frame Zero) not found 'CALCULATE SEGMENT LENGTH AND POSITION FILE POINTER TO LOOK AT NEXT SEGMENT READ(JpgFile,segLenHI) READ(JpgFile,segLenLO) segLen=256*(segLenHI&255)+(segLenLO&255) FilePos=SEEK(JpgFile) 'current File Position FilePos=FilePos+segLen-2 '-2=bytes into segment we've already read SEEK JpgFile,FilePos ENDIF UNTIL imageheight>0 | FilePos>=JpgLength CLOSEFILE JpgFile ENDIF IF imageheight>0 aspectratio=FLT(imagewidth)/imageheight ENDIF RETURN aspectratio ENDSUB