86 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoCollapse;
89 window_flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize;
92 ImGui::SetNextWindowSizeConstraints(ImVec2(ImGui::GetIO().DisplaySize.x * 0.1, ImGui::GetIO().DisplaySize.y * 0.1), ImVec2(ImGui::GetIO().DisplaySize.x - 200, ImGui::GetIO().DisplaySize.y));
99 float minScale = 0.10f, maxScale = 10.0f;
101 ImGui::TextUnformatted(
"Default Marker Size Scale");
103 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
104 if (ImGui::SliderFloat(
"##marker_size_slider", &
global_size_slider, minScale, maxScale,
"x%.2f"))
116 float minScale = 25.0f, maxScale = 550.0f;
118 ImGui::TextUnformatted(
"Directory Thumb Pixel Size");
120 ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
121 if (ImGui::SliderFloat(
"##image_size_slider", &
imageSize, minScale, maxScale,
"x%.2f"))
132 ImGui::BeginChild(
"DirectoryScrollRegion", ImVec2(0, 0),
true, ImGuiWindowFlags_HorizontalScrollbar);
133 float window_width = ImGui::GetWindowWidth();
134 ImVec2 content_region = ImGui::GetContentRegionAvail();
135 int columns = (int)(content_region.x /
imageSize);
141 std::shared_lock<std::shared_mutex> lock(
imagesMutex);
142 for (
auto& image :
images)
144 if (count % columns != 0)
146 std::string path_file =
directoryPath +
"\\" + image.filename.c_str();
147 if (image.textureID == 0)
153 ImGui::PushID(count);
158 if (ImGui::ImageButton((
void*)(intptr_t)image.textureID, ImVec2(
imageSize,
imageSize)))
161 std::cout <<
"Selected Image: " << image.
filename <<
" | " << image.textureID << std::endl;
162 ImGui::OpenPopup(
"Image Popup");
166 if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
168 ImGui::SetDragDropPayload(
"MARKER_IMAGE", &image,
sizeof(image));
169 ImGui::Text(
"Drag Marker: %s", image.filename.c_str());
170 ImGui::EndDragDropSource();
175 if (ImGui::ImageButton((
void*)(intptr_t)image.textureID, ImVec2(
imageSize,
imageSize)))
178 std::cout <<
"Selected Image: " << image.
filename <<
" | " << image.textureID << std::endl;
179 ImGui::OpenPopup(
"Image Popup");
182 if (ImGui::BeginPopup(
"Image Popup"))
184 ImGui::Text(
"File: %s", image.filename.c_str());
188 ImGui::TextWrapped(
"%s",
TruncateString(image.filename.c_str(), 16).c_str());
260 std::vector<std::string> removals;
261 std::vector<std::pair<std::string, std::string>> adds;
263 std::lock_guard<std::mutex> qlk(pendingMtx);
264 removals.swap(pendingRemovals);
265 adds.swap(pendingAddPaths);
269 if (!removals.empty())
271 std::unique_lock<std::shared_mutex> lk(imagesMutex);
272 for (
const auto& fname : removals)
274 auto it = std::find_if(images.begin(), images.end(),
276 { return im.filename == fname; });
277 if (it != images.end())
279 if (it->textureID != 0)
280 glDeleteTextures(1, &it->textureID);
290 std::vector<ImageData> toInsert;
291 toInsert.reserve(adds.size());
293 for (
auto& [fname, fullpath] : adds)
297 for (
int i = 0; i < 10; ++i)
299 std::ifstream f(fullpath, std::ios::binary);
305 std::this_thread::sleep_for(std::chrono::milliseconds(50));
311 ImageData img = LoadTextureFromFile(fullpath.c_str());
312 if (img.textureID != 0)
314 img.filename = fname;
315 toInsert.emplace_back(std::move(img));
319 if (!toInsert.empty())
321 std::unique_lock<std::shared_mutex> lk(imagesMutex);
322 for (
auto& im : toInsert)
325 auto it = std::find_if(images.begin(), images.end(),
327 { return x.filename == im.filename; });
328 if (it == images.end())
329 images.emplace_back(std::move(im));
358 using namespace std::chrono_literals;
361 std::vector<std::string> knownFiles;
363 while (running.load(std::memory_order_relaxed))
365 std::vector<std::string> currentFiles;
368 for (
const auto& entry : std::filesystem::directory_iterator(path))
370 if (entry.is_regular_file())
372 currentFiles.push_back(entry.path().filename().string());
376 catch (
const std::filesystem::filesystem_error& e)
378 std::cerr <<
"[DirectoryWindow] Filesystem error: " << e.what() << std::endl;
382 for (
const auto& name : knownFiles)
384 if (std::find(currentFiles.begin(), currentFiles.end(), name) == currentFiles.end())
386 std::lock_guard<std::mutex> qlk(pendingMtx);
387 pendingRemovals.emplace_back(name);
392 for (
const auto& name : currentFiles)
394 if (std::find(knownFiles.begin(), knownFiles.end(), name) == knownFiles.end())
396 const std::string full = (std::filesystem::path(path) / name).
string();
397 std::lock_guard<std::mutex> qlk(pendingMtx);
398 pendingAddPaths.emplace_back(name, full);
402 knownFiles = std::move(currentFiles);
405 first_scan_done =
true;
407 std::this_thread::sleep_for(2s);
417 int width, height, nrChannels;
418 unsigned char* data = stbi_load(path, &width, &height, &nrChannels, 4);
419 stbi_set_flip_vertically_on_load(0);
422 std::cerr <<
"Failed to load texture: " << path << std::endl;
427 glGenTextures(1, textureID);
428 glBindTexture(GL_TEXTURE_2D, textureID[0]);
431 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
433 GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
434 GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
435 GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
436 GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
438 stbi_image_free(data);
449 return ImageData(textureID[0], glm::vec2(width, height), path);