blob: 5e75365cf8a5507f1664b36b2c921f586ad8883a [file] [log] [blame]
William Wilgus90118f12019-07-26 01:30:00 -05001--[[
2/***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 * $Id$
10 *
11 * Copyright (C) 2017 William Wilgus
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22]]
23if ... == nil then rb.splash(rb.HZ * 3, "use 'require'") end
24require("printtable")
25local _lcd = require("lcd")
26local _timer = require("timer")
27
28--------------------------------------------------------------------------------
29--[[ returns a sorted tables of directories and (another) of files
30-- path is the starting path; norecurse == true.. only that path will be searched
31-- findfile & finddir are definable search functions
32-- if not defined all files/dirs are returned if false is passed.. none
33-- or you can provide your own function see below..
34-- f_t and d_t allow you to pass your own tables for re-use but isn't necessary
35]]
36local function get_files(path, norecurse, finddir, findfile, f_t, d_t)
37
38 local quit = false
39
40 local files = f_t or {}
41 local dirs = d_t or {}
42
43 local function f_filedir(name)
44 --default find function
45 -- example: return name:find(".mp3", 1, true) ~= nil
46 if name:len() <= 2 and (name == "." or name == "..") then
47 return false
48 end
49 return true
50 end
51 local function d_filedir(name)
52 --default discard function
53 return false
54 end
55
56 if finddir == nil then
57 finddir = f_filedir
58 elseif type(finddir) ~= "function" then
59 finddir = d_filedir
60 end
61
62 if findfile == nil then
63 findfile = f_filedir
64 elseif type(findfile) ~= "function" then
65 findfile = d_filedir
66 end
67
68 local function _get_files(path, cancelbtn)
69 local sep = ""
70 if string.sub(path, - 1) ~= "/" then sep = "/" end
71 for fname, isdir in luadir.dir(path) do
72
73 if isdir and finddir(fname) then
74 table.insert(dirs, path .. sep ..fname)
75 elseif not isdir and findfile(fname) then
76 table.insert(files, path .. sep ..fname)
77 end
78
79 if rb.get_plugin_action(0) == cancelbtn then
80 return true
81 end
82 end
83 end
84
85 local function cmp_alphanum (op1, op2)
86 local type1= type(op1)
87 local type2 = type(op2)
88
89 if type1 ~= type2 then
90 return type1 < type2
91 else
92 if type1 == "string" then
93 op1 = op1:upper()
94 op2 = op2:upper()
95 end
96 return op1 < op2
97 end
98 end
99
100 _lcd:splashf(1, "Searching for Files")
101
102 table.insert(dirs, path) -- root
103
104 for key,value in pairs(dirs) do
105 --luadir.dir may error out so we need to do the call protected
106 _, quit = pcall(_get_files, value, CANCEL_BUTTON)
107
108 if quit == true or norecurse then
109 break;
110 end
111 end
112
113 table.sort(files, cmp_alphanum)
114 table.sort(dirs, cmp_alphanum)
115
116 return dirs, files
117end -- get_files
118--------------------------------------------------------------------------------
119
120-- uses print_table and get_files to display simple file browser
121function file_choose(dir, title)
122 local dstr, hstr = ""
123 if not title then
124 dstr = "%d items found in %0d.%02d seconds"
125 else
126 hstr = title
127 end
128
129 -- returns whole seconds and remainder
130 local function tick2seconds(ticks)
131 local secs = (ticks / rb.HZ)
132 local csecs = (ticks - (secs * rb.HZ))
133 return secs, csecs
134 end
135
136 local norecurse = true
137 local f_finddir = nil -- function to match directories; nil all, false none
138 local f_findfile = nil -- function to match files; nil all, false none
139
140 local p_settings = {wrap = true, hasheader = true}
141
142 local timer
143 local files = {}
144 local dirs = {}
145 local item = 1
146 _lcd:clear()
147
148 while item > 0 do
149 if not title then
150 timer = _timer()
151 end
152
153 dirs, files = get_files(dir, norecurse, f_finddir, f_findfile, dirs, files)
154
155 local parentdir = dirs[1]
156 for i = 1, #dirs do
157 dirs[i] = "\t" .. dirs[i]
158 end
159
160 for i = 1, #files do
161 table.insert(dirs, "\t" .. files[i])
162 end
163
164 for i=1, #files do files[i] = nil end -- empty table for reuse
165
166 if not title then
167 hstr = string.format(dstr, #dirs - 1, tick2seconds(timer:stop()))
168 end
169
170 table.insert(dirs, 1, hstr)
171
172 item = print_table(dirs, #dirs, p_settings)
173
174 -- If item was selected follow directory or return filename
175 if item > 0 then
176 dir = string.gsub(dirs[item], "%c+","")
177 if not rb.dir_exists("/" .. dir) then
178 return dir
179 end
180 end
181
182 if dir == parentdir then
183 dir = dir:sub(1, dir:match(".*()/") - 1)
184 if dir == "" then dir = "/" end
185 end
186 for i=1, #dirs do dirs[i] = nil end -- empty table for reuse
187
188 end
189end -- file_choose
190--------------------------------------------------------------------------------