Перейти к содержимому

ДубоБлог

  • записей
    15
  • комментариев
    39
  • просмотров
    2 857

Файловый менеджер. Часть #2 [хождение по папкам]

Doob

306 просмотров


Чтобы отобразить иконки файлов и папок, а затем использовать их как кнопки, нужно разработать удобную в управлении структуру данных.

При помощи filesystem API можно получить контент текущей директории, что с этим делать?

 

Для начала разметим экран. В верхней части, на всю ширину экрана будет что-то вроде статус-бара высотой в 4 строки, там будет состояние памяти, батареи, может быть адресная и поисковая строка. Иконки 10x5 символов, с именем снизу, будут располагаться по сетке, через 1 символ.

xGp7sDC.png

 

Загруженные иконки уже хранятся в таблице, осталось назначить их файлам и нарисовать.

При загрузке программы надобно рассчитать, сколько иконок войдет по горизонтали и вертикали, создать таблицу для хранения сетки. Иконка начинает рисоваться от левого верхнего угла, поэтому в таблицу будем заносить именно эти начальные координаты.

Обзовем таблицу, например, grid.

В этой же таблице сделаем буфер для хранения имен иконок, чтобы при переходе из папки в папку не рисовать иконки, которые уже есть.

 

Кстати, все содержимое может не влезть на экран, поэтому будем его разбивать на страницы. Для этого создадим таблицу pages и при сканировании директории будем добавлять в нее таблицы с содержимым страницы, если количество файлов больше размерности #grid.

 

Сами страницы будут с такими же индексами, что и grid, по индексам будут хранится: имя файла или папки, назначенная иконка и флаг, директория это или нет.

 

Приступим к описанию функции обновления информации о содержимом.

Для начала обнулим страницы.

Получим текущую директорию при помощи filesystem.realPath(os.getenv('PWD')) или shell.getWorkingDirectory().

Для того, чтобы в результате получить привычный вид, надо будет отсортировать файлы отдельно от папок по алфавиту.

Для этого создадим две временные таблицы, просканируем директорию через filesystem.list(), если имя оканчивается символом '/', то кидаем его к папкам, иначе к файлам, затем сортируем обе таблицы обычным table.sort().

Добавляем имена папок к именам файлов в том же порядке, но в начало таблицы и начинаем обработку результата.

Обходим таблицу с именами файлов, если это папка, то назначаем иконку 'folder', если это ссылка, то 'link', во всех остальных случаях получаем расширение файла паттерном ([^%.]+)$ и пробуем назначить иконку с таким же названием.

Как-то лень было изучить работу lua-patterns, по идее он должен захватывать одно и больше вхождений, но захватывает от нуля, поэтому файлы с именем расширения, получают иконки.

Если расширения нет, назначается иконка 'unknown'.

Далее, в таблицу pages записываем имя файлв, имя иконки и флаг. Потом обновляем индекс, по условию индекс == размерность сетки сбрасываем индекс и обновляем счетчик страниц.


local W, H = gpu.getResolution() -- получить разрешение экрана
local grid, pages = {buffer = {}}, {{}} -- создать таблицу для сетки и страниц
local wm = math.floor(W/11) -- вычислить, сколько иконок войдет по горизонтали
local index = 1 -- создать счетчик
for Y = 1, math.floor((H*2-5)/14) do -- пройти цикл по вертикали
  for X = 1, wm do -- пройти цикл по горизонтали
    grid[index] = {x = X*11-9+(W-wm*11-1)/2, y = Y*7-2, z = Y*7+3} -- рассчитать и задать координаты для текущего индекса
    index = index + 1
  end
end

local function update()
  pages = {{}} -- обнулить страницы
  local index, page, pwd = 1, 1, os.getenv('PWD') -- создать счетчики и получить текущую директорию
  local names, folders = {}, {} -- создать таблицы для имен
  if fs.realPath(pwd) ~= '' then -- если текущая директория не корневая
    folders[1] = '..' -- добавить папку для перехода на верхний уровень
  end
  for name in fs.list(fs.realPath(pwd)) do -- получить имена в текущей папке
    if name:sub(-1) == '/' then -- если в конце слэш
      table.insert(folders, name) -- добавить к папкам
    else -- иначе
      table.insert(names, name) -- к файлам
    end
  end
  table.sort(folders) -- отсортировать имена папок
  table.sort(names) -- отсортировать имена файлов
  for i = #folders, 1, -1 do -- в цикле объеденить имена в одну таблицу
    table.insert(names, 1, folders[i])
  end
  folders = nil -- удалить таблицу для папок
  for n, name in pairs(names) do -- пройти по всем именам
    local icon, isDir -- создать переменные для имени иконки и флага
    if fs.isDirectory(pwd..'/'..name) then -- назначить иконку для папки
      icon, isDir = 'folder', true
    elseif fs.isLink(pwd..'/'..name) then -- назначить для ссылки
      icon = 'link'
    elseif icons[name:match('([^%.]+)$')] then -- если есть иконка для этого расширения
      icon = name:match('([^%.]+)$') -- назначить по имени
    else
      icon = 'unknown' -- для всех остальных назначить стандартную иконку
    end
    pages[page][index] = {name = name:gsub('/', ''), icon = icon, dir = isDir} -- записать имя, имя иконки и флаг в текущую страницу
    if index == #grid then -- если текущая страница заполнена
      index, page = 1, page + 1 -- обновить индекс и номер страницы
      pages[page] = {} -- создать страницу
    else
      index = index + 1 -- обновить индекс
    end
  end
end

 

Теперь надо отрисовать иконки по сетке.

В цикле пройдем по индексам сетки, из координат получим индекс для буфера, для быстрого обращения.

Если на текущей странице и с текущим индексом что-то есть, а в буфере по этим координатам другая иконка. Берем имя иконки и координаты сетки, вызываем функцию draw_icon(), записываем в буфер имя новой иконки.

Сбрасываем цвета, стираем зону, где будет имя файла. Пишем имя файла, со смещением, чтобы оно было примерно по центру иконки. Не забывая обрезать имя до 10 символов.

Если по текущему индексу на странице ничего нет, но в буфере осталось имя иконки. Стираем его из буфера. Устанавливаем фоновый цвет и заливаем иконку вместе с именем по  текущему индексу пустотой.

local function draw(page)
  page = page or 1 -- если страница не указана, назначить первую
  for index = 1, #grid do -- пройти по индексам сетки
    local hash = grid[index].x*W+grid[index].y -- получить хеш
    if pages[page][index] then -- если на странице по этому индексу есть запись
      if pages[page][index].icon ~= grid.buffer[hash] then -- если новая иконка отличается
        draw_icon(pages[page][index].icon, grid[index].x, grid[index].y) -- нарисовать иконку
        grid.buffer[hash] = pages[page][index].icon -- обновить буфер
      end
      local name = pages[page][index].name
      gpu.setBackground(0) -- задать фоновый цвет
      local color = 0xffffff -- задать цвет текста
      if pages[page][index].dir then -- если это папка
        color = 0xffff00 -- задать другой
      end
      gpu.setForeground(color) -- установить цвет
      gpu.fill(grid[index].x, grid[index].z, 10, 1, ' ') -- очистить место
      gpu.set(grid[index].x+5-#name:sub(1, 10)/2, grid[index].z, name:sub(1, 10)) -- написать имя
    else -- если страница кончилась
      if grid.buffer[hash] then -- если в буфере что-то есть
        grid.buffer[hash] = nil -- обновить буфер
        gpu.setBackground(0) -- задать фоновый цвет
        gpu.fill(grid[index].x, grid[index].y, 10, 6, ' ') -- очистить место
      end
    end
  end
end

 

Теперь можно добавить слушателей из части #0, очистить экран, вызвать update() и draw()

По событию 'click' запускать следующую конструкцию:

for index = 1, #grid do
  if grid[index].x <= e[3] and grid[index].x+10 >= e[3] and
    grid[index].y <= e[4] and grid[index].y+5 >= e[4] then
    if pages[1][index] then
      if pages[1][index].dir then
        shell.setWorkingDirectory(shell.getWorkingDirectory()..'/'..pages[1][index].name)
        update()
        draw()
        break
      end
    end
  end
end

 

Теперь можно ползать по диску.

a1eZPP8.gif

  • Нравится 2


2 комментария


Рекомендуемые комментарии

Прикольную тему делаешь, так держать! Собственно, о чем бишь я... Я не знаю какую ты прогу юзаешь, чтобы конвертить картинки в .ppm но решил запилить свою с блэкджеком и шлюхами, от нечего делать =) Собственно ссылки на сам конвертор (написан на Kotlin) и на мой гитлаб с исходниками:

Сам конвертор.

Исходники

P.S Если возникнут какие-то проблемы с прогой, то поймай меня в ирц или тут на форуме напиши в личку. =)

Изменено пользователем MeXaN1cK

Поделиться комментарием


Ссылка на комментарий

Дуб, а Дуб, когда же нам ждать продолжения то? =) Очень интересно было бы взглянуть на конечный продукт. Как я понял, осталось только добавить возможность создания/удаления файлов и папок ну и копирование/вырезание и вставку и вроде как оно будет очень интересным решением =)

Поделиться комментарием


Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Добавить комментарий...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...