ladybird/Userland/Libraries/LibGUI/ImageWidget.cpp
Andreas Kling d01b4327fa LibGfx: Improve ImageDecoder construction
Previously, ImageDecoder::create() would return a NonnullRefPtr and
could not "fail", although the returned decoder may be "invalid" which
you then had to check anyway.

The new interface looks like this:

    static RefPtr<Gfx::ImageDecoder> try_create(ReadonlyBytes);

This simplifies ImageDecoder since it no longer has to worry about its
validity. Client code gets slightly clearer as well.
2021-07-27 01:17:05 +02:00

130 lines
3.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/MappedFile.h>
#include <LibGUI/ImageWidget.h>
#include <LibGUI/Painter.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/ImageDecoder.h>
REGISTER_WIDGET(GUI, ImageWidget)
namespace GUI {
ImageWidget::ImageWidget(const StringView&)
: m_timer(Core::Timer::construct())
{
set_frame_thickness(0);
set_frame_shadow(Gfx::FrameShadow::Plain);
set_frame_shape(Gfx::FrameShape::NoFrame);
set_auto_resize(true);
REGISTER_BOOL_PROPERTY("auto_resize", auto_resize, set_auto_resize);
REGISTER_BOOL_PROPERTY("should_stretch", should_stretch, set_should_stretch);
}
ImageWidget::~ImageWidget()
{
}
void ImageWidget::set_bitmap(const Gfx::Bitmap* bitmap)
{
if (m_bitmap == bitmap)
return;
m_bitmap = bitmap;
if (m_bitmap && m_auto_resize)
set_fixed_size(m_bitmap->size());
update();
}
void ImageWidget::set_auto_resize(bool value)
{
m_auto_resize = value;
if (m_bitmap)
set_fixed_size(m_bitmap->size());
}
// Same as ImageViewer::ViewWidget::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();
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();
}
}
}
void ImageWidget::load_from_file(const StringView& path)
{
auto file_or_error = MappedFile::map(path);
if (file_or_error.is_error())
return;
auto& mapped_file = *file_or_error.value();
m_image_decoder = Gfx::ImageDecoder::try_create(mapped_file.bytes());
VERIFY(m_image_decoder);
auto bitmap = m_image_decoder->bitmap();
VERIFY(bitmap);
set_bitmap(bitmap);
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();
}
}
void ImageWidget::mousedown_event(GUI::MouseEvent&)
{
if (on_click)
on_click();
}
void ImageWidget::paint_event(PaintEvent& event)
{
Frame::paint_event(event);
if (!m_bitmap) {
return;
}
Painter painter(*this);
painter.add_clip_rect(event.rect());
if (m_should_stretch) {
painter.draw_scaled_bitmap(frame_inner_rect(), *m_bitmap, m_bitmap->rect(), (float)opacity_percent() / 100.0f);
} else {
auto location = frame_inner_rect().center().translated(-(m_bitmap->width() / 2), -(m_bitmap->height() / 2));
painter.blit(location, *m_bitmap, m_bitmap->rect(), (float)opacity_percent() / 100.0f);
}
}
void ImageWidget::set_opacity_percent(int percent)
{
if (m_opacity_percent == percent)
return;
m_opacity_percent = percent;
update();
}
}