diff --git a/Applications/FileManager/DirectoryModel.cpp b/Applications/FileManager/DirectoryModel.cpp index b079b048c3b..6cb65b913da 100644 --- a/Applications/FileManager/DirectoryModel.cpp +++ b/Applications/FileManager/DirectoryModel.cpp @@ -17,20 +17,29 @@ static HashMap>& thumbnail_cache() return *s_map; } -int thumbnail_thread(void* model) +int thumbnail_thread(void* model_ptr) { + auto& model = *(DirectoryModel*)model_ptr; for (;;) { sleep(1); + Vector to_generate; for (auto& it : thumbnail_cache()) { if (it.value) continue; - if (auto png_bitmap = GraphicsBitmap::load_from_file(it.key)) { - auto thumbnail = GraphicsBitmap::create(png_bitmap->format(), { 32, 32 }); - Painter painter(*thumbnail); - painter.draw_scaled_bitmap(thumbnail->rect(), *png_bitmap, png_bitmap->rect()); - it.value = move(thumbnail); - ((DirectoryModel*)model)->did_update(); - } + to_generate.append(it.key); + } + for (int i = 0; i < to_generate.size(); ++i) { + auto& path = to_generate[i]; + auto png_bitmap = GraphicsBitmap::load_from_file(path); + if (!png_bitmap) + continue; + auto thumbnail = GraphicsBitmap::create(png_bitmap->format(), { 32, 32 }); + Painter painter(*thumbnail); + painter.draw_scaled_bitmap(thumbnail->rect(), *png_bitmap, png_bitmap->rect()); + thumbnail_cache().set(path, move(thumbnail)); + if (model.on_thumbnail_progress) + model.on_thumbnail_progress(i + 1, to_generate.size()); + model.did_update(); } } } @@ -109,7 +118,7 @@ GIcon DirectoryModel::icon_for(const Entry& entry) const return m_socket_icon; if (entry.mode & S_IXUSR) return m_executable_icon; - if (entry.name.ends_with(".png")) { + if (entry.name.to_lowercase().ends_with(".png")) { if (!entry.thumbnail) { auto path = entry.full_path(*this); auto it = thumbnail_cache().find(path); @@ -286,7 +295,7 @@ void DirectoryModel::activate(const GModelIndex& index) return; } - if (path.string().ends_with(".png")) { + if (path.string().to_lowercase().ends_with(".png")) { if (fork() == 0) { int rc = execl("/bin/qs", "/bin/qs", path.string().characters(), nullptr); if (rc < 0) diff --git a/Applications/FileManager/DirectoryModel.h b/Applications/FileManager/DirectoryModel.h index 4196cd586a4..1e3774a0c04 100644 --- a/Applications/FileManager/DirectoryModel.h +++ b/Applications/FileManager/DirectoryModel.h @@ -33,6 +33,8 @@ public: void open(const String& path); size_t bytes_in_files() const { return m_bytes_in_files; } + Function on_thumbnail_progress; + private: DirectoryModel(); diff --git a/Applications/FileManager/DirectoryTableView.cpp b/Applications/FileManager/DirectoryTableView.cpp index f11546f474f..ca27e549320 100644 --- a/Applications/FileManager/DirectoryTableView.cpp +++ b/Applications/FileManager/DirectoryTableView.cpp @@ -29,6 +29,11 @@ DirectoryView::DirectoryView(GWidget* parent) } }; + m_model->on_thumbnail_progress = [this] (int done, int total) { + if (on_thumbnail_progress) + on_thumbnail_progress(done, total); + }; + set_view_mode(ViewMode::Icon); } diff --git a/Applications/FileManager/DirectoryTableView.h b/Applications/FileManager/DirectoryTableView.h index 67b6ee5b175..564d8592371 100644 --- a/Applications/FileManager/DirectoryTableView.h +++ b/Applications/FileManager/DirectoryTableView.h @@ -19,6 +19,7 @@ public: Function on_path_change; Function on_status_message; + Function on_thumbnail_progress; enum ViewMode { Invalid, List, Icon }; void set_view_mode(ViewMode); diff --git a/Applications/FileManager/main.cpp b/Applications/FileManager/main.cpp index 9395ef5b224..2ba63bc3a63 100644 --- a/Applications/FileManager/main.cpp +++ b/Applications/FileManager/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,11 @@ int main(int argc, char** argv) auto* directory_view = new DirectoryView(widget); auto* statusbar = new GStatusBar(widget); + auto* progressbar = new GProgressBar(statusbar); + progressbar->set_caption("Generating thumbnails: "); + progressbar->set_format(GProgressBar::Format::ValueSlashMax); + progressbar->set_visible(false); + location_textbox->on_return_pressed = [directory_view] (auto& editor) { directory_view->open(editor.text()); }; @@ -138,6 +144,16 @@ int main(int argc, char** argv) statusbar->set_text(move(message)); }; + directory_view->on_thumbnail_progress = [&] (int done, int total) { + if (done == total) { + progressbar->set_visible(false); + return; + } + progressbar->set_range(0, total); + progressbar->set_value(done); + progressbar->set_visible(true); + }; + directory_view->open("/"); directory_view->set_focus(true); diff --git a/Base/res/icons/32x32/filetype-image.png b/Base/res/icons/32x32/filetype-image.png index 2e219bf46bd..9db1487c0b9 100644 Binary files a/Base/res/icons/32x32/filetype-image.png and b/Base/res/icons/32x32/filetype-image.png differ diff --git a/LibGUI/GProgressBar.cpp b/LibGUI/GProgressBar.cpp index c83952187c1..a0aa7b07f03 100644 --- a/LibGUI/GProgressBar.cpp +++ b/LibGUI/GProgressBar.cpp @@ -1,5 +1,6 @@ #include #include +#include GProgressBar::GProgressBar(GWidget* parent) : GWidget(parent) @@ -45,7 +46,15 @@ void GProgressBar::paint_event(GPaintEvent& event) // Then we draw the progress text over the gradient. // We draw it twice, once offset (1, 1) for a drop shadow look. - auto progress_text = String::format("%d%%", (int)(progress * 100)); + StringBuilder builder; + builder.append(m_caption); + if (m_format == Format::Percentage) + builder.appendf("%d%%", (int)(progress * 100)); + else if (m_format == Format::ValueSlashMax) + builder.appendf("%d/%d", m_value, m_max); + + auto progress_text = builder.to_string(); + painter.draw_text(rect().translated(1, 1), progress_text, TextAlignment::Center, Color::Black); painter.draw_text(rect(), progress_text, TextAlignment::Center, Color::White); diff --git a/LibGUI/GProgressBar.h b/LibGUI/GProgressBar.h index 6768e288719..4e34f29c4e2 100644 --- a/LibGUI/GProgressBar.h +++ b/LibGUI/GProgressBar.h @@ -12,11 +12,20 @@ public: int value() const { return m_value; } + String caption() const { return m_caption; } + void set_caption(const String& caption) { m_caption = caption; } + + enum Format { Percentage, ValueSlashMax }; + Format format() const { return m_format; } + void set_format(Format format) { m_format = format; } + protected: virtual void paint_event(GPaintEvent&) override; private: + Format m_format { Percentage }; int m_min { 0 }; int m_max { 100 }; int m_value { 0 }; + String m_caption; }; diff --git a/LibGUI/GWidget.cpp b/LibGUI/GWidget.cpp index 0dcb5e7ca50..fc5177ebdd5 100644 --- a/LibGUI/GWidget.cpp +++ b/LibGUI/GWidget.cpp @@ -336,6 +336,7 @@ void GWidget::invalidate_layout() return; if (!w->main_widget()) return; + do_layout(); w->main_widget()->do_layout(); }