mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 12:32:43 +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; | ||||
| } | ||||
| 
 | ||||
| int thumbnail_thread(void* model) | ||||
| int thumbnail_thread(void* model_ptr) | ||||
| { | ||||
|     auto& model = *(DirectoryModel*)model_ptr; | ||||
|     for (;;) { | ||||
|         sleep(1); | ||||
|         Vector<String> 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) | ||||
|  |  | |||
|  | @ -33,6 +33,8 @@ public: | |||
|     void open(const String& path); | ||||
|     size_t bytes_in_files() const { return m_bytes_in_files; } | ||||
| 
 | ||||
|     Function<void(int done, int total)> on_thumbnail_progress; | ||||
| 
 | ||||
| private: | ||||
|     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); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ public: | |||
| 
 | ||||
|     Function<void(const String&)> on_path_change; | ||||
|     Function<void(String)> on_status_message; | ||||
|     Function<void(int done, int total)> on_thumbnail_progress; | ||||
| 
 | ||||
|     enum ViewMode { Invalid, List, Icon }; | ||||
|     void set_view_mode(ViewMode); | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include <LibGUI/GLabel.h> | ||||
| #include <LibGUI/GInputBox.h> | ||||
| #include <LibGUI/GMessageBox.h> | ||||
| #include <LibGUI/GProgressBar.h> | ||||
| #include <unistd.h> | ||||
| #include <signal.h> | ||||
| #include <stdio.h> | ||||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
										
											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 <SharedGraphics/Painter.h> | ||||
| #include <AK/StringBuilder.h> | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
| }; | ||||
|  |  | |||
|  | @ -336,6 +336,7 @@ void GWidget::invalidate_layout() | |||
|         return; | ||||
|     if (!w->main_widget()) | ||||
|         return; | ||||
|     do_layout(); | ||||
|     w->main_widget()->do_layout(); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling