Serenity Operating System
at master 131 lines 3.7 kB view raw
1/* 2 * Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <LibCore/MappedFile.h> 9#include <LibCore/MimeData.h> 10#include <LibGUI/ImageWidget.h> 11#include <LibGUI/Painter.h> 12#include <LibGfx/Bitmap.h> 13#include <LibGfx/ImageDecoder.h> 14 15REGISTER_WIDGET(GUI, ImageWidget) 16 17namespace GUI { 18 19ImageWidget::ImageWidget(StringView) 20 : m_timer(Core::Timer::try_create().release_value_but_fixme_should_propagate_errors()) 21 22{ 23 set_frame_thickness(0); 24 set_frame_shadow(Gfx::FrameShadow::Plain); 25 set_frame_shape(Gfx::FrameShape::NoFrame); 26 set_auto_resize(true); 27 28 REGISTER_BOOL_PROPERTY("auto_resize", auto_resize, set_auto_resize); 29 REGISTER_BOOL_PROPERTY("should_stretch", should_stretch, set_should_stretch); 30 REGISTER_WRITE_ONLY_STRING_PROPERTY("bitmap", load_from_file); 31} 32 33void ImageWidget::set_bitmap(Gfx::Bitmap const* bitmap) 34{ 35 if (m_bitmap == bitmap) 36 return; 37 38 m_bitmap = bitmap; 39 if (m_bitmap && m_auto_resize) 40 set_fixed_size(m_bitmap->size()); 41 42 update(); 43} 44 45void ImageWidget::set_auto_resize(bool value) 46{ 47 m_auto_resize = value; 48 49 if (m_bitmap) 50 set_fixed_size(m_bitmap->size()); 51} 52 53// Same as ImageViewer::ViewWidget::animate(), you probably want to keep any changes in sync 54void ImageWidget::animate() 55{ 56 m_current_frame_index = (m_current_frame_index + 1) % m_image_decoder->frame_count(); 57 58 auto current_frame = m_image_decoder->frame(m_current_frame_index).release_value_but_fixme_should_propagate_errors(); 59 set_bitmap(current_frame.image); 60 61 if (current_frame.duration != m_timer->interval()) { 62 m_timer->restart(current_frame.duration); 63 } 64 65 if (m_current_frame_index == m_image_decoder->frame_count() - 1) { 66 ++m_loops_completed; 67 if (m_loops_completed > 0 && m_loops_completed == m_image_decoder->loop_count()) { 68 m_timer->stop(); 69 } 70 } 71} 72 73void ImageWidget::load_from_file(StringView path) 74{ 75 auto file_or_error = Core::MappedFile::map(path); 76 if (file_or_error.is_error()) 77 return; 78 79 auto& mapped_file = *file_or_error.value(); 80 auto mime_type = Core::guess_mime_type_based_on_filename(path); 81 m_image_decoder = Gfx::ImageDecoder::try_create_for_raw_bytes(mapped_file.bytes(), mime_type); 82 VERIFY(m_image_decoder); 83 84 auto frame = m_image_decoder->frame(0).release_value_but_fixme_should_propagate_errors(); 85 auto bitmap = frame.image; 86 VERIFY(bitmap); 87 88 set_bitmap(bitmap); 89 90 if (m_image_decoder->is_animated() && m_image_decoder->frame_count() > 1) { 91 auto first_frame = m_image_decoder->frame(0).release_value_but_fixme_should_propagate_errors(); 92 m_timer->set_interval(first_frame.duration); 93 m_timer->on_timeout = [this] { animate(); }; 94 m_timer->start(); 95 } 96} 97 98void ImageWidget::mousedown_event(GUI::MouseEvent&) 99{ 100 if (on_click) 101 on_click(); 102} 103 104void ImageWidget::paint_event(PaintEvent& event) 105{ 106 Frame::paint_event(event); 107 108 if (!m_bitmap) { 109 return; 110 } 111 112 Painter painter(*this); 113 painter.add_clip_rect(event.rect()); 114 115 if (m_should_stretch) { 116 painter.draw_scaled_bitmap(frame_inner_rect(), *m_bitmap, m_bitmap->rect(), (float)opacity_percent() / 100.0f); 117 } else { 118 auto location = frame_inner_rect().center().translated(-(m_bitmap->width() / 2), -(m_bitmap->height() / 2)); 119 painter.blit(location, *m_bitmap, m_bitmap->rect(), (float)opacity_percent() / 100.0f); 120 } 121} 122 123void ImageWidget::set_opacity_percent(int percent) 124{ 125 if (m_opacity_percent == percent) 126 return; 127 m_opacity_percent = percent; 128 update(); 129} 130 131}