/* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2021, Linus Groh * Copyright (c) 2021, Mohsan Ali * Copyright (c) 2022, Mustafa Quraish * Copyright (c) 2022, the SerenityOS developers. * Copyright (c) 2023, Caoimhe Byrne * Copyright (c) 2023, MacDue * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include namespace ImageViewer { class Image : public RefCounted { public: virtual Gfx::IntSize size() const = 0; virtual Gfx::IntRect rect() const { return { {}, size() }; } virtual void flip(Gfx::Orientation) = 0; virtual void rotate(Gfx::RotationDirection) = 0; virtual void draw_into(Gfx::Painter&, Gfx::IntRect const& dest, Gfx::Painter::ScalingMode) const = 0; virtual ErrorOr> bitmap(Optional ideal_size) const = 0; virtual ~Image() = default; }; class VectorImage final : public Image { public: static NonnullRefPtr create(Gfx::VectorGraphic& vector) { return adopt_ref(*new VectorImage(vector)); } virtual Gfx::IntSize size() const override { return m_size; } virtual void flip(Gfx::Orientation) override; virtual void rotate(Gfx::RotationDirection) override; virtual void draw_into(Gfx::Painter&, Gfx::IntRect const& dest, Gfx::Painter::ScalingMode) const override; virtual ErrorOr> bitmap(Optional ideal_size) const override; private: VectorImage(Gfx::VectorGraphic& vector) : m_vector(vector) , m_size(vector.size()) { } void apply_transform(Gfx::AffineTransform transform) { m_transform = transform.multiply(m_transform); } NonnullRefPtr m_vector; Gfx::IntSize m_size; Gfx::AffineTransform m_transform; }; class BitmapImage final : public Image { public: static NonnullRefPtr create(Gfx::Bitmap& bitmap, Gfx::FloatPoint scale) { return adopt_ref(*new BitmapImage(bitmap, scale)); } virtual Gfx::IntSize size() const override { return { round(m_bitmap->size().width() * m_scale.x()), round(m_bitmap->size().height() * m_scale.y()) }; } virtual void flip(Gfx::Orientation) override; virtual void rotate(Gfx::RotationDirection) override; virtual void draw_into(Gfx::Painter&, Gfx::IntRect const& dest, Gfx::Painter::ScalingMode) const override; virtual ErrorOr> bitmap(Optional) const override { return m_bitmap; } private: BitmapImage(Gfx::Bitmap& bitmap, Gfx::FloatPoint scale) : m_bitmap(bitmap) , m_scale(scale) { } NonnullRefPtr m_bitmap; Gfx::FloatPoint m_scale; }; class ViewWidget final : public GUI::AbstractZoomPanWidget { C_OBJECT(ViewWidget) public: enum Directions { First, Back, Forward, Last }; virtual ~ViewWidget() override = default; Image const* image() const { return m_image.ptr(); } String const& path() const { return m_path; } void set_toolbar_height(int height) { m_toolbar_height = height; } int toolbar_height() { return m_toolbar_height; } bool scaled_for_first_image() { return m_scaled_for_first_image; } void set_scaled_for_first_image(bool val) { m_scaled_for_first_image = val; } void set_path(String const& path); void resize_window(); void scale_image_for_window(); void set_scaling_mode(Gfx::Painter::ScalingMode); bool is_next_available() const; bool is_previous_available() const; void clear(); void flip(Gfx::Orientation); void rotate(Gfx::RotationDirection); void navigate(Directions); void open_file(String const&, Core::File&); Function on_doubleclick; Function on_drop; Function on_image_change; private: ViewWidget(); virtual void doubleclick_event(GUI::MouseEvent&) override; virtual void paint_event(GUI::PaintEvent&) override; virtual void mousedown_event(GUI::MouseEvent&) override; virtual void mouseup_event(GUI::MouseEvent&) override; virtual void drag_enter_event(GUI::DragEvent&) override; virtual void drop_event(GUI::DropEvent&) override; virtual void resize_event(GUI::ResizeEvent&) override; void set_image(Image const* image); void animate(); Vector load_files_from_directory(ByteString const& path) const; ErrorOr try_open_file(String const&, Core::File&); String m_path; RefPtr m_image; struct Animation { struct Frame { RefPtr image; int duration { 0 }; }; size_t loop_count { 0 }; Vector frames; }; Optional m_animation; size_t m_current_frame_index { 0 }; size_t m_loops_completed { 0 }; NonnullRefPtr m_timer; int m_toolbar_height { 28 }; bool m_scaled_for_first_image { false }; Vector m_files_in_same_dir; Optional m_current_index; Gfx::Painter::ScalingMode m_scaling_mode { Gfx::Painter::ScalingMode::NearestNeighbor }; }; }