summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Groh <mail@linusgroh.de>2021-03-16 23:37:44 +0100
committerAndreas Kling <kling@serenityos.org>2021-03-17 12:37:48 +0100
commit10843a2c8cec6cd3bbb0b14a84fe1a19eee89808 (patch)
treed13daac7a8ec6d254792384c6be2bf1379482776
parent41e51554679dcc72c235ac44f466c1d7f738fc40 (diff)
downloadserenity-10843a2c8cec6cd3bbb0b14a84fe1a19eee89808.zip
QuickShow: Animate animated images :^)
With a little help (read: copy & paste) from ImageWidget, QuickShow will now cycle through the frames of animated images - enjoy the cat GIFs! Future improvement: cache decoded images like LibWeb's ImageResource to waste less CPU - the same applies to LibGUI though, maybe we can put something shared in LibGfx. Closes #5837.
-rw-r--r--Userland/Applications/QuickShow/QSWidget.cpp56
-rw-r--r--Userland/Applications/QuickShow/QSWidget.h18
-rw-r--r--Userland/Libraries/LibGUI/ImageWidget.cpp1
3 files changed, 67 insertions, 8 deletions
diff --git a/Userland/Applications/QuickShow/QSWidget.cpp b/Userland/Applications/QuickShow/QSWidget.cpp
index 6cc2c125ab..7a52e43fe6 100644
--- a/Userland/Applications/QuickShow/QSWidget.cpp
+++ b/Userland/Applications/QuickShow/QSWidget.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Linus Groh <mail@linusgroh.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -25,16 +26,18 @@
*/
#include "QSWidget.h"
+#include <AK/MappedFile.h>
#include <AK/StringBuilder.h>
#include <LibCore/DirIterator.h>
+#include <LibCore/Timer.h>
#include <LibGUI/MessageBox.h>
#include <LibGUI/Painter.h>
-#include <LibGUI/Window.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/Orientation.h>
#include <LibGfx/Palette.h>
QSWidget::QSWidget()
+ : m_timer(Core::Timer::construct())
{
set_fill_with_background_color(false);
}
@@ -244,12 +247,31 @@ void QSWidget::mousewheel_event(GUI::MouseEvent& event)
void QSWidget::load_from_file(const String& path)
{
- auto bitmap = Gfx::Bitmap::load_from_file(path);
- if (!bitmap) {
+ auto show_error = [&] {
GUI::MessageBox::show(window(), String::formatted("Failed to open {}", path), "Cannot open image", GUI::MessageBox::Type::Error);
+ };
+
+ auto file_or_error = MappedFile::map(path);
+ if (file_or_error.is_error()) {
+ show_error();
+ return;
+ }
+
+ auto& mapped_file = *file_or_error.value();
+ m_image_decoder = Gfx::ImageDecoder::create((const u8*)mapped_file.data(), mapped_file.size());
+ auto bitmap = m_image_decoder->bitmap();
+ if (!bitmap) {
+ show_error();
return;
}
+ if (m_image_decoder->is_animated() && m_image_decoder->frame_count() > 1) {
+ const auto& first_frame = m_image_decoder->frame(0);
+ m_timer->set_interval(first_frame.duration);
+ m_timer->on_timeout = [this] { animate(); };
+ m_timer->start();
+ }
+
m_path = path;
m_bitmap = bitmap;
m_scale = -1;
@@ -287,3 +309,31 @@ void QSWidget::reset_view()
m_pan_origin = { 0, 0 };
set_scale(100);
}
+
+void QSWidget::set_bitmap(const Gfx::Bitmap* bitmap)
+{
+ if (m_bitmap == bitmap)
+ return;
+ m_bitmap = bitmap;
+ update();
+}
+
+// Same as ImageWidget::animate(), you probably want to keep any changes in sync
+void QSWidget::animate()
+{
+ m_current_frame_index = (m_current_frame_index + 1) % m_image_decoder->frame_count();
+
+ const auto& current_frame = m_image_decoder->frame(m_current_frame_index);
+ set_bitmap(current_frame.image);
+
+ if (current_frame.duration != m_timer->interval()) {
+ m_timer->restart(current_frame.duration);
+ }
+
+ if (m_current_frame_index == m_image_decoder->frame_count() - 1) {
+ ++m_loops_completed;
+ if (m_loops_completed > 0 && m_loops_completed == m_image_decoder->loop_count()) {
+ m_timer->stop();
+ }
+ }
+}
diff --git a/Userland/Applications/QuickShow/QSWidget.h b/Userland/Applications/QuickShow/QSWidget.h
index 57bc346f5b..c39ceb9f4b 100644
--- a/Userland/Applications/QuickShow/QSWidget.h
+++ b/Userland/Applications/QuickShow/QSWidget.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
+ * Copyright (c) 2021, Linus Groh <mail@linusgroh.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,12 +27,12 @@
#pragma once
+#include <LibCore/Timer.h>
#include <LibGUI/Frame.h>
#include <LibGfx/Bitmap.h>
+#include <LibGfx/ImageDecoder.h>
#include <LibGfx/Point.h>
-class QSLabel;
-
class QSWidget final : public GUI::Frame {
C_OBJECT(QSWidget)
public:
@@ -72,18 +73,25 @@ private:
virtual void mousewheel_event(GUI::MouseEvent&) override;
virtual void drop_event(GUI::DropEvent&) override;
+ void set_bitmap(const Gfx::Bitmap* bitmap);
+
void relayout();
void resize_window();
void reset_view();
+ void animate();
String m_path;
RefPtr<Gfx::Bitmap> m_bitmap;
- int m_toolbar_height { 28 };
-
Gfx::IntRect m_bitmap_rect;
+
+ RefPtr<Gfx::ImageDecoder> m_image_decoder;
+ size_t m_current_frame_index { 0 };
+ size_t m_loops_completed { 0 };
+ NonnullRefPtr<Core::Timer> m_timer;
+
int m_scale { -1 };
+ int m_toolbar_height { 28 };
Gfx::FloatPoint m_pan_origin;
-
Gfx::IntPoint m_click_position;
Gfx::FloatPoint m_saved_pan_origin;
Vector<String> m_files_in_same_dir;
diff --git a/Userland/Libraries/LibGUI/ImageWidget.cpp b/Userland/Libraries/LibGUI/ImageWidget.cpp
index 218c09a809..24f68398e7 100644
--- a/Userland/Libraries/LibGUI/ImageWidget.cpp
+++ b/Userland/Libraries/LibGUI/ImageWidget.cpp
@@ -71,6 +71,7 @@ void ImageWidget::set_auto_resize(bool value)
set_fixed_size(m_bitmap->size());
}
+// Same as QSWidget::animate(), you probably want to keep any changes in sync
void ImageWidget::animate()
{
m_current_frame_index = (m_current_frame_index + 1) % m_image_decoder->frame_count();