FileListBox proxy gadget

BlitzMax Forums/BlitzMax GUI Programming/FileListBox proxy gadget

A pretty simple file browsing gadget.

I just use this as an Import, but it should work with no real changes as a module. Is there a way to get these sorts of things added to the official proxy gadget module? It'd be great if we could all contribute the gadgets we've made as proxy gadgets for others to use - built right in.

I don't really know bbdoc, so that part might not be right, but I'm kinda tired. I will however probably update this as I use it for a project tomorrow.

As of now I've only really tested this on Linux, but it should work on Windows and Max OS. If not let me know and I will update it.

Enjoy.

Screenshot:


Update: Oct-4-2008: Added a few functions to let you get the item string (removing the square brackets from directories and getting the parent if .. is selected) or full filename of any item based on index - not just the selected item. Also fixed a bug where the style argument wasn't used to create the actual list box.

fileListBox.bmx
Strict

Import MaxGUI.MaxGUI

Rem
bbdoc: Creates a list box that allows browsing for files or folders.
about: The underlying gadget is a listbox, and so the @style parameter can take all the #CreateListBox flags.

When creating the file list box, you must specify the initial directory it should display. this can be changed
with #ChangeDir.

The current dir is always available as the <b>.dir</b> property, updated to match whatever navigation the user
has done.

Set <b>.showDotFiles</b> to true to show files and directories that start with a period. By default these
files are hidden.

The following events are emited by this gadget:

<table>
<tr><td>EVENT_GADGETACTION</td><td>When the user activates a file by pressing enter or double clicking.</td></tr>
<tr><td>EVENT_GADGETOPEN</td><td>When the user navigates to a child directory.</td></tr>
<tr><td>EVENT_GADGETCLOSE</td><td>When the user navigates to a parent directory.</td></tr>
</tr>
</table>
End Rem
Function CreateFileListBox:TGadget( dir$,x,y,w,h,group:TGadget,style=0)
	
	Return New TFileListBox.Create(dir,x,y,w,h,group,style)
	
EndFunction

Type TFileListBox Extends TProxyGadget
	
	Global instances:TList
	
	Field dir:String
	Field lstBox:TGadget
	Field showDotFiles:Int = False
	
	Method New()
		If Not instances Then Initialize()
	EndMethod
	
	Method Create:TFileListBox(pdir$,x,y,w,h,group:TGadget,style)
		
		lstBox = CreateListBox(x,y,w,h,group,style)
		SetDir(pdir)
		
		'DebugStop
		SetProxy( lstBox )
		
		instances.AddLast Self
		
		Return Self
		
	EndMethod
	
	Method EventHook:TEvent( pEvent:TEvent )
		
		Select pEvent.id
			Case EVENT_GADGETACTION
				Local item:String = GetSelectedItem()
				Local file:String = GetSelectedFilename()
				If FileType(file) = 2 Then
					SetDir(file)
					If item = ".." Then
						Return CreateEvent(EVENT_GADGETCLOSE, Self)
					Else
						Return CreateEvent(EVENT_GADGETOPEN, Self)
					EndIf
				Else
					Return pEvent
				EndIf
			'Default
			'	Print pEvent.id
		EndSelect
		
		Return Null
	
	EndMethod
	
Rem
bbdoc: Set the directory shown by the list box.
bbabout: Automatically calls refreshes after setting the new path.
End Rem
	Method SetDir(pdir:String)
		dir = pdir
		If dir[Len(dir)-1..] <> "/" Then dir = dir + "/"
		Refresh()
	EndMethod
	
Rem
bbdoc: Return the selected file by itself without it's path.
bbabout: To get the full path, call #GetSelectedFilename
End Rem
	Method GetSelectedItem:String()
		Local idx:Int = SelectedGadgetItem(lstBox)
		Return GetItem(idx)
	EndMethod
	
Rem
bbdoc: Return the given file in the list by itself without it's path.
bbabout: To get the full path, call #GetFilename
End Rem
	Method GetItem:String(idx:Int)
		Local result:String = ""
		
		If idx > -1 Then
			result = GadgetItemText(lstBox, idx)
			If result[..1] = "[" Then
				result = result[1..Len(result)-1]
			EndIf
		EndIf
		
		Return result
	EndMethod
	

Rem
bbdoc: Return the full path to the selected file or directory.
bbabout: To get just the item without the path, call #GetSelectedItem.
End Rem
	Method GetSelectedFilename:String()
		Local idx:Int = SelectedGadgetItem(lstBox)
		Return GetFilename(idx)
	EndMethod
	
Rem
bbdoc: Return the full path to a paticular file or directory in the list.
bbabout: To get just the item without the path, call #GetItem.
End Rem
	Method GetFilename:String(idx:Int)
		Local result:String = ""
		Local item:String = GetItem(idx)
		
		If item <> "" Then
			If item = ".." Then
				result = ExtractDir(ExtractDir(dir))
			Else
				result = dir + item
			EndIf
		EndIf
		Return result
	EndMethod
	
Rem
bbdoc: Refresh the contents of the list box.
End Rem
	Method Refresh()
		Local dirs:String[]
		Local files:String[]
		Local selectedItem:String = GetSelectedItem()
		Local hDir:Int
		Local i:Int
		Local item:String
		
		ClearGadgetItems(lstBox)

		'files = LoadDir(dir)
		'files.Sort()
		
		' Get directory listing - sorting into subdirectories and files
		hDir = ReadDir(dir)
		item = NextFile(hDir)
		While item <> ""
			If item <> "." And item <> ".." Then
				'Print dir + item
				If FileType(dir + item) = 2 Then
					dirs = dirs[..Len(dirs)+1]
					dirs[Len(dirs)-1] = item
				Else
					files = files[..Len(files)+1]
					files[Len(files)-1] = item
				EndIf
			EndIf
			item = NextFile(hDir)
		EndWhile
		CloseDir(hDir)
		
		' Sort the two groups independently
		dirs.Sort()
		files.Sort()
		
		' Add the parent item
		AddGadgetItem(lstBox, "[..]")
		' Add directories
		_AddItems(dirs, selectedItem)
		' Add files
		_AddItems(files, selectedItem)
	EndMethod
	
	Method _AddItems(files:String[], selectItem:String)
		Local i:Int
		Local item:String
		
		If files <> Null Then
			For i = 0 To Len(files)-1
				If files[i][..1] <> "." Or showDotFiles Then
					If FileType(dir + "/" + files[i]) = 2 Then
						item = "[" + files[i] + "]"
					Else
						item = files[i]
					EndIf
					AddGadgetItem(lstBox, item)
					If item = selectItem Then SelectGadgetItem(lstBox, i)
				EndIf
			Next
		EndIf
	EndMethod
	
	Method CleanUp()
		instances.Remove(Self)
		Super.CleanUp()
	EndMethod
	
	Function Initialize()
		instances = New TList
		AddHook EmitEventHook, eventHandler, Null, 1
	EndFunction
	
	Function eventHandler:Object( pID%, pData:Object, pContext:Object )
		Local pEvent:TEvent = TEvent(pData)
		
		If pEvent Then
			'If pevent.id = EVENT_GADGETACTION Then DebugStop
			For Local tmpGadget:TFileListBox = EachIn instances
				If tmpGadget = pEvent.source Then
					'Print "found proxy"
					Return tmpGadget.EventHook( pEvent )
				EndIf
			Next
		EndIf
		
		Return pData
	EndFunction
	
EndType


Example:
Import MaxGUI.Drivers
Import "fileListBox.bmx"
Global MainWindow:TGadget
Global fileListBox:TFileListBox

MainWindow=CreateWindow("FileListBox test",10,50,185,247,Desktop(),WINDOW_TITLEBAR|WINDOW_RESIZABLE)

fileListBox = TFileListBox(CreateFileListBox("/",0,0,185,247,MainWindow,LISTBOX_MULTISELECT))
SetGadgetLayout fileListBox,1,1,1,1


Repeat
	Select WaitEvent()
		Case EVENT_WINDOWCLOSE
			Exit
		Case EVENT_GADGETACTION
			If EventSource() = fileListBox Then
				Notify "Open a file: " + fileListBox.GetSelectedFilename()
			EndIf
		Case EVENT_GADGETCLOSE
			If EventSource() = fileListBox Then
				Notify "Moved up a directory. Current dir: " + fileListBox.dir
			EndIf
		Case EVENT_GADGETOPEN
			If EventSource() = fileListBox Then
				Notify "Moved down a directory. Current dir: " + fileListBox.dir
			EndIf
	End Select
Forever


That one looks handy :)