Files
reilua-enhanced/examples/raygui_examples/file_browser.lua

384 lines
8.6 KiB
Lua

local FileBrowser = {}
FileBrowser.__index = FileBrowser
FileBrowser.MODES = {
OPEN = 1,
SAVE = 2,
}
FileBrowser.FILE_ICONS = {
DIR = 1,
FILE = 10,
[".wav"] = 11,
[".mp3"] = 11,
[".ogg"] = 11,
[".mid"] = 11,
[".png"] = 12,
[".jpg"] = 12,
[".jpeg"] = 12,
[".avi"] = 13,
[".mov"] = 13,
[".mp4"] = 13,
[".exe"] = 142,
}
function FileBrowser:new( pos )
local object = setmetatable( {}, FileBrowser )
object.padding = 4
object.spacing = 4
object.controls = {}
object.callbacks = {} -- open.
local winSize = Vec2:new( 600, 490 )
local iconButtonSize = Vec2:new( 28, 28 )
local textButtonSize = Vec2:new( 72, 28 )
-- Window.
object.window = Gui:WindowBox(
Rect:new( pos.x, pos.y, winSize.x, winSize.y ),
"File Browser",
{ -- callbacks.
close = function() object:setVisible( false ) end,
grab = function() object:setToTop() end,
drag = function( this ) object:setPosition( Vec2:new( this.bounds.x, this.bounds.y ) ) end
}
)
-- Ok button.
object.okButton = Gui:Button(
Rect:new( 0, 0, textButtonSize.x, textButtonSize.y ),
"Open",
{ -- callbacks.
pressed = function() object:ok() end
}
)
object.okButton.position = Vec2:new(
winSize.x - textButtonSize.x - object.padding,
winSize.y - textButtonSize.y - object.padding
)
-- Filter dropdown.
object.filterDropdown = Gui:DropdownBox(
Rect:new( 0, 0, textButtonSize.x, textButtonSize.y ),
"All\n.png\n.lua\n.wav\n.ogg\n.txt",
0, -- active.
false, -- editMode.
{ -- callbacks.
select = function() object:setFilter() end
},
{ -- styles.
properties = {
{ RL.DROPDOWNBOX, RL.TEXT_ALIGNMENT, RL.TEXT_ALIGN_LEFT },
{ RL.DROPDOWNBOX, RL.TEXT_PADDING, 8 },
}
}
)
object.filterDropdown.position = Vec2:new(
winSize.x - textButtonSize.x * 2 - object.padding * 2,
winSize.y - textButtonSize.y - object.padding
)
-- Back button.
object.backButton = Gui:Button(
Rect:new( 0, 0, iconButtonSize.x, iconButtonSize.y ),
RL.GuiIconText( 118, "" ),
{ -- callbacks.
pressed = function() object:back() end
}
)
object.backButton.position = Vec2:new(
winSize.x - iconButtonSize.x - object.padding,
Gui.RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + object.padding
)
-- Search button.
object.searchToggle = Gui:Toggle(
Rect:new( 0, 0, iconButtonSize.x, iconButtonSize.y ),
RL.GuiIconText( 42, "" ),
false, -- active.
{ -- callbacks.
pressed = function( this ) object:searchPressed( this.active ) end
}
)
object.searchToggle.position = Vec2:new(
winSize.x - iconButtonSize.x * 2 - object.padding * 2,
Gui.RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + object.padding
)
-- Path text box.
object.pathBox = Gui:TextBox(
Rect:new( 0, 0, winSize.x - iconButtonSize.x * 2 - object.padding * 4, iconButtonSize.y ),
"",
256,
false,
{ -- callbacks.
-- edit = function() object:editPathCallback() end,
textEdit = function() object:editPathCallback() end
}
)
object.pathBox.position = Vec2:new(
object.padding,
Gui.RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + object.padding
)
-- File text box.
object.fileBox = Gui:TextBox(
Rect:new( 0, 0, winSize.x - textButtonSize.x * 2 - object.padding * 4, iconButtonSize.y ),
"",
256,
false,
{ -- callbacks.
-- edit = function() object:checkPath() end
}
)
object.fileBox.position = Vec2:new(
object.padding,
winSize.y - object.okButton.bounds.height - object.padding
)
-- File List.
object.list = Gui:ListView(
Rect:new( 0, 0,
winSize.x - object.padding * 2,
winSize.y - Gui.RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - textButtonSize.y
- object.pathBox.bounds.height - object.padding * 3 - object.spacing
),
"",
0, -- scrollIndex.
0, -- active.
{ -- callbacks.
select = function() object:select() end
},
{ -- styles
properties = {
{ RL.LISTVIEW, RL.TEXT_ALIGNMENT, RL.TEXT_ALIGN_LEFT }
}
}
)
object.list.position = Vec2:new(
object.padding,
object.pathBox.position.y + object.pathBox.bounds.height + object.padding
)
table.insert( object.controls, object.okButton )
table.insert( object.controls, object.filterDropdown )
table.insert( object.controls, object.backButton )
table.insert( object.controls, object.searchToggle )
table.insert( object.controls, object.list )
table.insert( object.controls, object.pathBox )
table.insert( object.controls, object.fileBox )
object.filter = nil
object.path = ""
object.file = ""
object.searchText = ""
object.files = {}
object.lastActive = 0
object.mode = self.MODES.OPEN
object:setPosition( pos )
object:setVisible( false )
return object
end
function FileBrowser:popup( mode, path, callback, filters )
self:setPath( path )
self.mode = mode
if self.mode == self.MODES.OPEN then
self.okButton.text = "Open"
self.callbacks.ok = callback
end
if filters ~= nil then
self.filterDropdown.text = "All\n"..filters
end
self:setVisible( true )
end
function FileBrowser:editPathCallback()
if self.searchToggle.active then
self.searchText = self.pathBox.text
self:updateList()
else
self:checkPath()
end
end
function FileBrowser:checkPath()
local path = self.pathBox.text
self.searchToggle.active = false
self.searchText = ""
if RL.FileExists( path ) and not RL.IsPathFile( path ) then
self:setPath( path )
end
end
function FileBrowser:back()
if self.searchToggle.active then
return
end
for i = #self.pathBox.text, 1, -1 do
if self.pathBox.text:sub( i, i ) == "/" and i < #self.pathBox.text then
self.pathBox.text = self.pathBox.text:sub( 1, math.max( 1, i - 1 ) )
self:checkPath()
return
end
end
end
function FileBrowser:setPath( path )
if path:sub( 1, 2 ) == "//" then
path = path:sub( 2 )
end
self.lastActive = 0
self.list.active = -1
self.pathBox.text = path
self.path = path
self:updateList()
end
function FileBrowser:updateList()
self.list.text = ""
self.files = {}
local files = RL.LoadDirectoryFilesEx( self.path, self.filter, false )
table.sort( files, function( a, b ) return a < b end )
for i = #files, 1, -1 do
local filePath = files[i]
-- Don't add unix hidden files.
if RL.GetFileName( filePath ):sub( 1, 1 ) ~= "." then
local record = {
path = filePath,
name = RL.GetFileName( filePath ),
isFile = RL.IsPathFile( filePath ),
sortValue = i
}
if record.isFile then
record.sortValue = record.sortValue + #files
end
-- Search.
if self.searchText == "" or ( 0 < #self.searchText
and -1 < RL.TextFindIndex( record.name:lower(), self.searchText:lower() ) ) then
table.insert( self.files, record )
end
end
end
table.sort( self.files, function( a, b ) return a.sortValue < b.sortValue end )
for i, file in ipairs( self.files ) do
local icon = self.FILE_ICONS.DIR
if file.isFile then
local ext = RL.GetFileExtension( file.name )
if self.FILE_ICONS[ ext ] ~= nil then
icon = self.FILE_ICONS[ ext ]
else
icon = self.FILE_ICONS.FILE
end
end
self.list.text = self.list.text..RL.GuiIconText( icon, file.name )
if i < #self.files then
self.list.text = self.list.text.."\n"
end
end
end
function FileBrowser:select()
local index = self.list.active + 1
local lastFile = self.files[ self.lastActive ]
if 0 < index then
self.file = self.files[ index ].path
self.fileBox.text = self.files[ index ].name
elseif lastFile ~= nil then
-- Trigger if active pressed again, so index would be 0.
if index == 0 then
if RL.IsPathFile( lastFile.path ) then
self:ok()
else
self.pathBox.text = lastFile.path
self:checkPath()
end
end
end
self.lastActive = index
end
function FileBrowser:ok()
if self.mode == self.MODES.OPEN then
if RL.IsPathFile( self.file ) then
if self.callbacks.ok ~= nil then
self.callbacks.ok( self.file )
end
else
self.pathBox.text = self.file
self:checkPath()
end
end
end
function FileBrowser:searchPressed( active )
if active then
self.pathBox.text = self.searchText
self.pathBox.active = true
Gui:editMode( self.pathBox ) -- Would not call edit callback if had one.
self.pathBox.editMode = true
else
self.searchText = ""
self.pathBox.text = self.path
self:checkPath()
end
end
function FileBrowser:setFilter()
if self.filterDropdown.active == 0 then
self.filter = nil
else
self.filter = self.filterDropdown:getItem( self.filterDropdown.active )
end
self:updateList()
end
function FileBrowser:setPosition( pos )
for _, control in ipairs( self.controls ) do
control:setPosition( pos + control.position )
end
end
function FileBrowser:setToTop()
Gui:setToTop( self.window )
for _, control in ipairs( self.controls ) do
Gui:setToTop( control )
end
end
function FileBrowser:setVisible( visible )
self.visible = visible
self.window.visible = visible
for _, control in ipairs( self.controls ) do
control.visible = visible
end
end
return FileBrowser