1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 08:27:35 +00:00

DisplaySettings: Improve wallpaper preview code

Previously, this code would create a bitmap with the size of the screen
resolution, draw the new wallpaper into it, and then scale it down for
display inside the MonitorWidget.

This was done on every paint event, which made the code quite slow and
allocation-happy.

Instead of this, we now scale down the new wallpaper to a miniature
of the same scale as the little MonitorWidget screen. The miniature is
then used for tiling, etc. The miniature is cached and reused across
paint events if nothing else changes.
This commit is contained in:
Andreas Kling 2021-05-20 17:43:33 +02:00
parent df5f382b50
commit 3046b3467c
2 changed files with 55 additions and 25 deletions

View file

@ -19,17 +19,21 @@ MonitorWidget::MonitorWidget()
{
m_desktop_resolution = GUI::Desktop::the().rect().size();
m_monitor_bitmap = Gfx::Bitmap::load_from_file("/res/graphics/monitor.png");
m_monitor_rect = { 12, 13, 280, 158 };
m_desktop_bitmap = Gfx::Bitmap::create(m_monitor_bitmap->format(), { 280, 158 });
m_monitor_rect = { { 12, 13 }, m_desktop_bitmap->size() };
set_fixed_size(304, 201);
}
bool MonitorWidget::set_wallpaper(String path)
{
auto bitmap_ptr = Gfx::Bitmap::load_from_file(path);
if (!bitmap_ptr && !path.is_empty())
if (path.is_empty())
return false;
auto bitmap = Gfx::Bitmap::load_from_file(path);
if (!bitmap)
return false;
m_desktop_wallpaper_path = move(path);
m_desktop_wallpaper_bitmap = bitmap_ptr;
m_wallpaper_bitmap = move(bitmap);
m_desktop_dirty = true;
update();
return true;
}
@ -44,6 +48,7 @@ void MonitorWidget::set_wallpaper_mode(String mode)
if (m_desktop_wallpaper_mode == mode)
return;
m_desktop_wallpaper_mode = move(mode);
m_desktop_dirty = true;
update();
}
@ -54,7 +59,11 @@ String MonitorWidget::wallpaper_mode()
void MonitorWidget::set_desktop_resolution(Gfx::IntSize resolution)
{
if (m_desktop_resolution == resolution)
return;
m_desktop_resolution = resolution;
m_desktop_dirty = true;
update();
}
Gfx::IntSize MonitorWidget::desktop_resolution()
@ -67,6 +76,7 @@ void MonitorWidget::set_background_color(Gfx::Color color)
if (m_desktop_color == color)
return;
m_desktop_color = color;
m_desktop_dirty = true;
update();
}
@ -75,33 +85,49 @@ Gfx::Color MonitorWidget::background_color()
return m_desktop_color;
}
void MonitorWidget::paint_event(GUI::PaintEvent& event)
void MonitorWidget::redraw_desktop_if_needed()
{
Gfx::IntRect screen_rect = { { 0, 0 }, m_desktop_resolution };
auto screen_bitmap = Gfx::Bitmap::create(m_monitor_bitmap->format(), m_desktop_resolution);
GUI::Painter screen_painter(*screen_bitmap);
screen_painter.fill_rect(screen_rect, m_desktop_color);
if (!m_desktop_dirty)
return;
m_desktop_dirty = false;
GUI::Painter painter(*m_desktop_bitmap);
painter.fill_rect(m_desktop_bitmap->rect(), m_desktop_color);
if (!m_wallpaper_bitmap)
return;
float sw = (float)m_desktop_bitmap->width() / (float)m_desktop_resolution.width();
float sh = (float)m_desktop_bitmap->height() / (float)m_desktop_resolution.height();
auto scaled_size = m_wallpaper_bitmap->size().to_type<float>().scaled_by(sw, sh).to_type<int>();
auto scaled_bitmap = m_wallpaper_bitmap->scaled(sw, sh);
if (!m_desktop_wallpaper_bitmap.is_null()) {
if (m_desktop_wallpaper_mode == "simple") {
screen_painter.blit({ 0, 0 }, *m_desktop_wallpaper_bitmap, m_desktop_wallpaper_bitmap->rect());
painter.blit({}, *scaled_bitmap, scaled_bitmap->rect());
} else if (m_desktop_wallpaper_mode == "center") {
Gfx::IntPoint offset { (screen_rect.width() - m_desktop_wallpaper_bitmap->width()) / 2, (screen_rect.height() - m_desktop_wallpaper_bitmap->height()) / 2 };
screen_painter.blit_offset(screen_rect.location(), *m_desktop_wallpaper_bitmap, screen_rect, offset);
Gfx::IntRect centered_rect { {}, scaled_size };
centered_rect.center_within(m_desktop_bitmap->rect());
painter.blit(centered_rect.location(), *scaled_bitmap, scaled_bitmap->rect());
} else if (m_desktop_wallpaper_mode == "tile") {
screen_painter.draw_tiled_bitmap(screen_bitmap->rect(), *m_desktop_wallpaper_bitmap);
painter.draw_tiled_bitmap(m_desktop_bitmap->rect(), *scaled_bitmap);
} else if (m_desktop_wallpaper_mode == "stretch") {
screen_painter.draw_scaled_bitmap(screen_bitmap->rect(), *m_desktop_wallpaper_bitmap, m_desktop_wallpaper_bitmap->rect());
painter.draw_scaled_bitmap(m_desktop_bitmap->rect(), *m_wallpaper_bitmap, m_wallpaper_bitmap->rect());
} else {
VERIFY_NOT_REACHED();
}
}
void MonitorWidget::paint_event(GUI::PaintEvent& event)
{
redraw_desktop_if_needed();
GUI::Painter painter(*this);
painter.add_clip_rect(event.rect());
painter.blit({ 0, 0 }, *m_monitor_bitmap, m_monitor_bitmap->rect());
painter.draw_scaled_bitmap(m_monitor_rect, *screen_bitmap, screen_bitmap->rect());
painter.blit(m_monitor_rect.location(), *m_desktop_bitmap, m_desktop_bitmap->rect());
#if 0
if (!m_desktop_resolution.is_null()) {

View file

@ -32,13 +32,17 @@ public:
private:
MonitorWidget();
void redraw_desktop_if_needed();
virtual void paint_event(GUI::PaintEvent& event) override;
Gfx::IntRect m_monitor_rect;
RefPtr<Gfx::Bitmap> m_monitor_bitmap;
RefPtr<Gfx::Bitmap> m_desktop_bitmap;
bool m_desktop_dirty { true };
String m_desktop_wallpaper_path;
RefPtr<Gfx::Bitmap> m_desktop_wallpaper_bitmap;
RefPtr<Gfx::Bitmap> m_wallpaper_bitmap;
String m_desktop_wallpaper_mode;
Gfx::IntSize m_desktop_resolution;
int m_desktop_scale_factor { 1 };