From b96960a1f97f815a6872fedc422ea950ed477cda Mon Sep 17 00:00:00 2001 From: jussi Date: Fri, 29 Mar 2024 20:51:43 +0200 Subject: Raygui lib examples file browser. --- examples/raygui_examples/file_browser.lua | 380 ++++++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 examples/raygui_examples/file_browser.lua (limited to 'examples/raygui_examples/file_browser.lua') diff --git a/examples/raygui_examples/file_browser.lua b/examples/raygui_examples/file_browser.lua new file mode 100644 index 0000000..cdecfb0 --- /dev/null +++ b/examples/raygui_examples/file_browser.lua @@ -0,0 +1,380 @@ +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:set2Top() 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 ) + self:setPath( path ) + self.mode = mode + + if self.mode == self.MODES.OPEN then + self.okButton.text = "Open" + self.callbacks.ok = callback + 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 self.searchText:lower() == record.name:sub( 1, #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() + print( "self.filter", self.filter ) +end + +function FileBrowser:setPosition( pos ) + for _, control in ipairs( self.controls ) do + control:setPosition( pos + control.position ) + end +end + +function FileBrowser:set2Top() + Gui:set2Top( self.window ) + + for _, control in ipairs( self.controls ) do + Gui:set2Top( 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 -- cgit v1.2.3