mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 21:52:45 +00:00 
			
		
		
		
	FileManager+LibGUI: Show thumbnail generation progress in the statusbar.
This commit is contained in:
		
							parent
							
								
									32191b0d4b
								
							
						
					
					
						commit
						614dafea32
					
				
					 9 changed files with 63 additions and 11 deletions
				
			
		|  | @ -17,20 +17,29 @@ static HashMap<String, RetainPtr<GraphicsBitmap>>& thumbnail_cache() | ||||||
|     return *s_map; |     return *s_map; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int thumbnail_thread(void* model) | int thumbnail_thread(void* model_ptr) | ||||||
| { | { | ||||||
|  |     auto& model = *(DirectoryModel*)model_ptr; | ||||||
|     for (;;) { |     for (;;) { | ||||||
|         sleep(1); |         sleep(1); | ||||||
|  |         Vector<String> to_generate; | ||||||
|         for (auto& it : thumbnail_cache()) { |         for (auto& it : thumbnail_cache()) { | ||||||
|             if (it.value) |             if (it.value) | ||||||
|                 continue; |                 continue; | ||||||
|             if (auto png_bitmap = GraphicsBitmap::load_from_file(it.key)) { |             to_generate.append(it.key); | ||||||
|                 auto thumbnail = GraphicsBitmap::create(png_bitmap->format(), { 32, 32 }); |         } | ||||||
|                 Painter painter(*thumbnail); |         for (int i = 0; i < to_generate.size(); ++i) { | ||||||
|                 painter.draw_scaled_bitmap(thumbnail->rect(), *png_bitmap, png_bitmap->rect()); |             auto& path = to_generate[i]; | ||||||
|                 it.value = move(thumbnail); |             auto png_bitmap = GraphicsBitmap::load_from_file(path); | ||||||
|                 ((DirectoryModel*)model)->did_update(); |             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; |         return m_socket_icon; | ||||||
|     if (entry.mode & S_IXUSR) |     if (entry.mode & S_IXUSR) | ||||||
|         return m_executable_icon; |         return m_executable_icon; | ||||||
|     if (entry.name.ends_with(".png")) { |     if (entry.name.to_lowercase().ends_with(".png")) { | ||||||
|         if (!entry.thumbnail) { |         if (!entry.thumbnail) { | ||||||
|             auto path = entry.full_path(*this); |             auto path = entry.full_path(*this); | ||||||
|             auto it = thumbnail_cache().find(path); |             auto it = thumbnail_cache().find(path); | ||||||
|  | @ -286,7 +295,7 @@ void DirectoryModel::activate(const GModelIndex& index) | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (path.string().ends_with(".png")) { |     if (path.string().to_lowercase().ends_with(".png")) { | ||||||
|         if (fork() == 0) { |         if (fork() == 0) { | ||||||
|             int rc = execl("/bin/qs", "/bin/qs", path.string().characters(), nullptr); |             int rc = execl("/bin/qs", "/bin/qs", path.string().characters(), nullptr); | ||||||
|             if (rc < 0) |             if (rc < 0) | ||||||
|  |  | ||||||
|  | @ -33,6 +33,8 @@ public: | ||||||
|     void open(const String& path); |     void open(const String& path); | ||||||
|     size_t bytes_in_files() const { return m_bytes_in_files; } |     size_t bytes_in_files() const { return m_bytes_in_files; } | ||||||
| 
 | 
 | ||||||
|  |     Function<void(int done, int total)> on_thumbnail_progress; | ||||||
|  | 
 | ||||||
| private: | private: | ||||||
|     DirectoryModel(); |     DirectoryModel(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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); |     set_view_mode(ViewMode::Icon); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     Function<void(const String&)> on_path_change; |     Function<void(const String&)> on_path_change; | ||||||
|     Function<void(String)> on_status_message; |     Function<void(String)> on_status_message; | ||||||
|  |     Function<void(int done, int total)> on_thumbnail_progress; | ||||||
| 
 | 
 | ||||||
|     enum ViewMode { Invalid, List, Icon }; |     enum ViewMode { Invalid, List, Icon }; | ||||||
|     void set_view_mode(ViewMode); |     void set_view_mode(ViewMode); | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| #include <LibGUI/GLabel.h> | #include <LibGUI/GLabel.h> | ||||||
| #include <LibGUI/GInputBox.h> | #include <LibGUI/GInputBox.h> | ||||||
| #include <LibGUI/GMessageBox.h> | #include <LibGUI/GMessageBox.h> | ||||||
|  | #include <LibGUI/GProgressBar.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include <signal.h> | #include <signal.h> | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
|  | @ -50,6 +51,11 @@ int main(int argc, char** argv) | ||||||
|     auto* directory_view = new DirectoryView(widget); |     auto* directory_view = new DirectoryView(widget); | ||||||
|     auto* statusbar = new GStatusBar(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) { |     location_textbox->on_return_pressed = [directory_view] (auto& editor) { | ||||||
|         directory_view->open(editor.text()); |         directory_view->open(editor.text()); | ||||||
|     }; |     }; | ||||||
|  | @ -138,6 +144,16 @@ int main(int argc, char** argv) | ||||||
|         statusbar->set_text(move(message)); |         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->open("/"); | ||||||
|     directory_view->set_focus(true); |     directory_view->set_focus(true); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 871 B After Width: | Height: | Size: 301 B | 
|  | @ -1,5 +1,6 @@ | ||||||
| #include <LibGUI/GProgressBar.h> | #include <LibGUI/GProgressBar.h> | ||||||
| #include <SharedGraphics/Painter.h> | #include <SharedGraphics/Painter.h> | ||||||
|  | #include <AK/StringBuilder.h> | ||||||
| 
 | 
 | ||||||
| GProgressBar::GProgressBar(GWidget* parent) | GProgressBar::GProgressBar(GWidget* parent) | ||||||
|     : GWidget(parent) |     : GWidget(parent) | ||||||
|  | @ -45,7 +46,15 @@ void GProgressBar::paint_event(GPaintEvent& event) | ||||||
| 
 | 
 | ||||||
|     // Then we draw the progress text over the gradient.
 |     // Then we draw the progress text over the gradient.
 | ||||||
|     // We draw it twice, once offset (1, 1) for a drop shadow look.
 |     // 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().translated(1, 1), progress_text, TextAlignment::Center, Color::Black); | ||||||
|     painter.draw_text(rect(), progress_text, TextAlignment::Center, Color::White); |     painter.draw_text(rect(), progress_text, TextAlignment::Center, Color::White); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,11 +12,20 @@ public: | ||||||
| 
 | 
 | ||||||
|     int value() const { return m_value; } |     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: | protected: | ||||||
|     virtual void paint_event(GPaintEvent&) override; |     virtual void paint_event(GPaintEvent&) override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     Format m_format { Percentage }; | ||||||
|     int m_min { 0 }; |     int m_min { 0 }; | ||||||
|     int m_max { 100 }; |     int m_max { 100 }; | ||||||
|     int m_value { 0 }; |     int m_value { 0 }; | ||||||
|  |     String m_caption; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -336,6 +336,7 @@ void GWidget::invalidate_layout() | ||||||
|         return; |         return; | ||||||
|     if (!w->main_widget()) |     if (!w->main_widget()) | ||||||
|         return; |         return; | ||||||
|  |     do_layout(); | ||||||
|     w->main_widget()->do_layout(); |     w->main_widget()->do_layout(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling