From ccb0d000200b1fb61e8f1c8b52320bee7f2690d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=BCseyin=20ASLIT=C3=9CRK?= Date: Sun, 14 Jun 2020 11:04:58 +0300 Subject: [PATCH] LibGUI: Add a new GUI::Image component for display images New GUI::Image component for replace Label usage for icons and images. --- Libraries/LibGUI/CMakeLists.txt | 1 + Libraries/LibGUI/Image.cpp | 134 ++++++++++++++++++++++++++++++++ Libraries/LibGUI/Image.h | 70 +++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 Libraries/LibGUI/Image.cpp create mode 100644 Libraries/LibGUI/Image.h diff --git a/Libraries/LibGUI/CMakeLists.txt b/Libraries/LibGUI/CMakeLists.txt index 36c55e25ff..de933a5a15 100644 --- a/Libraries/LibGUI/CMakeLists.txt +++ b/Libraries/LibGUI/CMakeLists.txt @@ -30,6 +30,7 @@ set(SOURCES GroupBox.cpp Icon.cpp IconView.cpp + Image.cpp INILexer.cpp INISyntaxHighlighter.cpp InputBox.cpp diff --git a/Libraries/LibGUI/Image.cpp b/Libraries/LibGUI/Image.cpp new file mode 100644 index 0000000000..14ce0df59d --- /dev/null +++ b/Libraries/LibGUI/Image.cpp @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2020, Hüseyin Aslıtürk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Image.h" +#include +#include +#include +#include + +namespace GUI { + +Image::Image(const StringView&) + : m_timer(Core::Timer::construct()) + +{ + set_frame_thickness(0); + set_frame_shadow(Gfx::FrameShadow::Plain); + set_frame_shape(Gfx::FrameShape::NoFrame); + set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); + set_auto_resize(true); +} + +Image::~Image() +{ +} + +void Image::set_bitmap(const Gfx::Bitmap* bitmap) +{ + if (m_bitmap == bitmap) + return; + + m_bitmap = bitmap; + if (m_auto_resize) + set_preferred_size(m_bitmap->width(), m_bitmap->height()); + + update(); +} + +void Image::set_auto_resize(bool value) +{ + m_auto_resize = value; + + if (m_bitmap) + set_preferred_size(m_bitmap->width(), m_bitmap->height()); +} + +void Image::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 Image::load_from_file(const StringView& path) +{ + MappedFile mapped_file(path); + if (!mapped_file.is_valid()) + return; + + m_image_decoder = Gfx::ImageDecoder::create((const u8*)mapped_file.data(), mapped_file.size()); + auto bitmap = m_image_decoder->bitmap(); + ASSERT(bitmap); + + set_bitmap(bitmap); + + if (path.ends_with(".gif")) { + 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 Image::mousedown_event(GUI::MouseEvent&) +{ + if (on_click) + on_click(); +} + +void Image::paint_event(PaintEvent& event) +{ + Frame::paint_event(event); + + if (!m_bitmap) { + return; + } + + Painter painter(*this); + + if (m_should_stretch) { + painter.draw_scaled_bitmap(frame_inner_rect(), *m_bitmap, m_bitmap->rect()); + } else { + auto location = frame_inner_rect().center().translated(-(m_bitmap->width() / 2), -(m_bitmap->height() / 2)); + painter.blit(location, *m_bitmap, m_bitmap->rect()); + } +} +} diff --git a/Libraries/LibGUI/Image.h b/Libraries/LibGUI/Image.h new file mode 100644 index 0000000000..f78ab5ae44 --- /dev/null +++ b/Libraries/LibGUI/Image.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020, Hüseyin Aslıtürk + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +namespace GUI { + +class Image : public Frame { + C_OBJECT(Image) +public: + virtual ~Image() override; + + void set_bitmap(const Gfx::Bitmap*); + Gfx::Bitmap* bitmap() { return m_bitmap.ptr(); } + + void set_should_stretch(bool value) { m_should_stretch = value; } + bool should_stretch() const { return m_should_stretch; } + + void set_auto_resize(bool value); + bool auto_resize() const { return m_auto_resize; } + + void animate(); + void load_from_file(const StringView&); + + Function on_click; + +protected: + explicit Image(const StringView& text = {}); + + virtual void mousedown_event(GUI::MouseEvent&) override; + virtual void paint_event(PaintEvent&) override; + +private: + RefPtr m_bitmap; + bool m_should_stretch { false }; + bool m_auto_resize { false }; + + RefPtr m_image_decoder; + size_t m_current_frame_index { 0 }; + size_t m_loops_completed { 0 }; + NonnullRefPtr m_timer; +}; + +}