forked from Green-Sky/tomato
build file selector list in a thread
This commit is contained in:
parent
f18d716924
commit
ab40ef7cb1
@ -18,6 +18,12 @@ FileSelector::FileSelector(void) {
|
|||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileSelector::~FileSelector(void) {
|
||||||
|
if (_future_cache.valid()) {
|
||||||
|
_future_cache.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FileSelector::requestFile(
|
void FileSelector::requestFile(
|
||||||
std::function<bool(std::filesystem::path& path)>&& is_valid,
|
std::function<bool(std::filesystem::path& path)>&& is_valid,
|
||||||
std::function<void(const std::filesystem::path& path)>&& on_choose,
|
std::function<void(const std::filesystem::path& path)>&& on_choose,
|
||||||
@ -101,9 +107,32 @@ void FileSelector::render(void) {
|
|||||||
static const ImU32 dir_bg0_color = ImGui::GetColorU32(ImVec4(0.6, 0.6, 0.1, 0.15));
|
static const ImU32 dir_bg0_color = ImGui::GetColorU32(ImVec4(0.6, 0.6, 0.1, 0.15));
|
||||||
static const ImU32 dir_bg1_color = ImGui::GetColorU32(ImVec4(0.7, 0.7, 0.2, 0.15));
|
static const ImU32 dir_bg1_color = ImGui::GetColorU32(ImVec4(0.7, 0.7, 0.2, 0.15));
|
||||||
|
|
||||||
std::vector<std::filesystem::directory_entry> dirs;
|
bool start_new_collection_task {false};
|
||||||
std::vector<std::filesystem::directory_entry> files;
|
if (_future_cache.valid()) {
|
||||||
for (auto const& dir_entry : std::filesystem::directory_iterator(current_path)) {
|
if (_future_cache.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready) {
|
||||||
|
// data is ready
|
||||||
|
_current_cache = _future_cache.get();
|
||||||
|
|
||||||
|
// also queue a new one
|
||||||
|
start_new_collection_task = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
start_new_collection_task = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if cache still current
|
||||||
|
if (_current_cache.has_value() && _current_cache.value().file_path != current_path) {
|
||||||
|
// and drop it if not
|
||||||
|
_current_cache.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (start_new_collection_task) {
|
||||||
|
_future_cache = std::async(std::launch::async, [path = current_path, sorts_specs = ImGui::TableGetSortSpecs()](void) -> CachedData {
|
||||||
|
CachedData cd;
|
||||||
|
cd.file_path = path;
|
||||||
|
auto& dirs = cd.dirs;
|
||||||
|
auto& files = cd.files;
|
||||||
|
for (auto const& dir_entry : std::filesystem::directory_iterator(path)) {
|
||||||
if (dir_entry.is_directory()) {
|
if (dir_entry.is_directory()) {
|
||||||
dirs.push_back(dir_entry);
|
dirs.push_back(dir_entry);
|
||||||
} else if (dir_entry.is_regular_file()) {
|
} else if (dir_entry.is_regular_file()) {
|
||||||
@ -113,8 +142,7 @@ void FileSelector::render(void) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// do sorting here
|
// do sorting here
|
||||||
// TODO: cache the result (lol)
|
if (sorts_specs != nullptr && sorts_specs->SpecsCount >= 1) {
|
||||||
if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); sorts_specs != nullptr && sorts_specs->SpecsCount >= 1) {
|
|
||||||
switch (static_cast<SortID>(sorts_specs->Specs->ColumnUserID)) {
|
switch (static_cast<SortID>(sorts_specs->Specs->ColumnUserID)) {
|
||||||
break; case SortID::name:
|
break; case SortID::name:
|
||||||
if (sorts_specs->Specs->SortDirection == ImGuiSortDirection_Descending) {
|
if (sorts_specs->Specs->SortDirection == ImGuiSortDirection_Descending) {
|
||||||
@ -167,7 +195,20 @@ void FileSelector::render(void) {
|
|||||||
// we likely saw a file disapear
|
// we likely saw a file disapear
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto const& dir_entry : dirs) {
|
return cd;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_current_cache.has_value()) {
|
||||||
|
const auto& dirs = _current_cache.value().dirs;
|
||||||
|
const auto& files = _current_cache.value().files;
|
||||||
|
|
||||||
|
// dirs
|
||||||
|
ImGuiListClipper dirs_clipper;
|
||||||
|
dirs_clipper.Begin(dirs.size());
|
||||||
|
while (dirs_clipper.Step()) {
|
||||||
|
for (int row = dirs_clipper.DisplayStart; row < dirs_clipper.DisplayEnd; row++) {
|
||||||
|
const auto& dir_entry = dirs.at(row);
|
||||||
if (ImGui::TableNextColumn()) {
|
if (ImGui::TableNextColumn()) {
|
||||||
if (tmp_id & 0x01) {
|
if (tmp_id & 0x01) {
|
||||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, dir_bg0_color);
|
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, dir_bg0_color);
|
||||||
@ -201,33 +242,34 @@ void FileSelector::render(void) {
|
|||||||
ImGui::TextDisabled("%2d.%2d.%2d - %2d:%2d", ltime->tm_mday, ltime->tm_mon + 1, ltime->tm_year + 1900, ltime->tm_hour, ltime->tm_min);
|
ImGui::TextDisabled("%2d.%2d.%2d - %2d:%2d", ltime->tm_mday, ltime->tm_mon + 1, ltime->tm_year + 1900, ltime->tm_hour, ltime->tm_min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// files
|
// files
|
||||||
ImGuiListClipper files_clipper;
|
ImGuiListClipper files_clipper;
|
||||||
files_clipper.Begin(files.size());
|
files_clipper.Begin(files.size());
|
||||||
while (files_clipper.Step()) {
|
while (files_clipper.Step()) {
|
||||||
for (int row = files_clipper.DisplayStart; row < files_clipper.DisplayEnd; row++) {
|
for (int row = files_clipper.DisplayStart; row < files_clipper.DisplayEnd; row++) {
|
||||||
const auto& dir_entry = files.at(row);
|
const auto& file_entry = files.at(row);
|
||||||
if (ImGui::TableNextColumn()) {
|
if (ImGui::TableNextColumn()) {
|
||||||
ImGui::PushID(tmp_id++);
|
ImGui::PushID(tmp_id++);
|
||||||
if (ImGui::Selectable("F", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
if (ImGui::Selectable("F", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||||
_current_file_path = dir_entry.path();
|
_current_file_path = file_entry.path();
|
||||||
}
|
}
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::TableNextColumn()) {
|
if (ImGui::TableNextColumn()) {
|
||||||
ImGui::TextUnformatted(dir_entry.path().filename().generic_u8string().c_str());
|
ImGui::TextUnformatted(file_entry.path().filename().generic_u8string().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::TableNextColumn()) {
|
if (ImGui::TableNextColumn()) {
|
||||||
ImGui::TextDisabled("%s", std::to_string(dir_entry.file_size()).c_str());
|
ImGui::TextDisabled("%s", std::to_string(file_entry.file_size()).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::TableNextColumn()) {
|
if (ImGui::TableNextColumn()) {
|
||||||
const auto file_time_converted = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
|
const auto file_time_converted = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
|
||||||
dir_entry.last_write_time()
|
file_entry.last_write_time()
|
||||||
- decltype(dir_entry.last_write_time())::clock::now()
|
- decltype(file_entry.last_write_time())::clock::now()
|
||||||
+ std::chrono::system_clock::now()
|
+ std::chrono::system_clock::now()
|
||||||
);
|
);
|
||||||
const auto ctime = std::chrono::system_clock::to_time_t(file_time_converted);
|
const auto ctime = std::chrono::system_clock::to_time_t(file_time_converted);
|
||||||
@ -237,6 +279,15 @@ void FileSelector::render(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// render loading placeholder
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextUnformatted("-");
|
||||||
|
}
|
||||||
|
if (ImGui::TableNextColumn()) {
|
||||||
|
ImGui::TextUnformatted("... loading ...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,20 @@
|
|||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
struct FileSelector {
|
struct FileSelector {
|
||||||
std::filesystem::path _current_file_path = std::filesystem::canonical(".") / ""; // add /
|
std::filesystem::path _current_file_path = std::filesystem::canonical(".") / ""; // add /
|
||||||
|
|
||||||
|
struct CachedData {
|
||||||
|
std::filesystem::path file_path; // can be used to check against current
|
||||||
|
std::vector<std::filesystem::directory_entry> dirs;
|
||||||
|
std::vector<std::filesystem::directory_entry> files;
|
||||||
|
};
|
||||||
|
std::optional<CachedData> _current_cache;
|
||||||
|
std::future<CachedData> _future_cache;
|
||||||
|
|
||||||
bool _open_popup {false};
|
bool _open_popup {false};
|
||||||
|
|
||||||
std::function<bool(std::filesystem::path& path)> _is_valid = [](auto){ return true; };
|
std::function<bool(std::filesystem::path& path)> _is_valid = [](auto){ return true; };
|
||||||
@ -16,6 +26,7 @@ struct FileSelector {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
FileSelector(void);
|
FileSelector(void);
|
||||||
|
~FileSelector(void);
|
||||||
|
|
||||||
// TODO: supply hints
|
// TODO: supply hints
|
||||||
// HACK: until we supply hints, is_valid can modify
|
// HACK: until we supply hints, is_valid can modify
|
||||||
|
@ -25,7 +25,9 @@ void ImageViewerPopup::render(float) {
|
|||||||
ImGui::OpenPopup("Image##ImageViewerPopup");
|
ImGui::OpenPopup("Image##ImageViewerPopup");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ImGui::BeginPopup("Image##ImageViewerPopup", ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize)) {
|
// TODO: remplace with modal(?), pop up i limited to viewport in size
|
||||||
|
// or replace with fixed window where the image can be moved
|
||||||
|
if (!ImGui::BeginPopup("Image##ImageViewerPopup", ImGuiWindowFlags_NoDecoration)) {
|
||||||
_m = {}; // meh, event on close would be nice, but the reset is cheap
|
_m = {}; // meh, event on close would be nice, but the reset is cheap
|
||||||
_scale = 1.f;
|
_scale = 1.f;
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user