From 31ee20e1795eebd6a60c8c65df967f73a536799c Mon Sep 17 00:00:00 2001 From: Torstennator Date: Tue, 18 Jul 2023 14:25:33 +0200 Subject: [PATCH] PixelPaint: Allow bigger Brush-Tool sizes This patch allows a bigger brush tool size of 250 pixels and limits the cursor bitmap to a reasonable size so that its not much bigger than the image editor size. If the cursor is bigger as the editor it is rended with a red edge to indicate that the actual cursor is bigger than displayed. This change mitigates the OOM conditions when the cursor gets unusual big. --- .../PixelPaint/Tools/BrushTool.cpp | 37 +++++++++++++------ .../Applications/PixelPaint/Tools/BrushTool.h | 4 +- .../PixelPaint/Tools/EraseTool.cpp | 26 ++++++++----- .../Applications/PixelPaint/Tools/EraseTool.h | 1 + 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/Userland/Applications/PixelPaint/Tools/BrushTool.cpp b/Userland/Applications/PixelPaint/Tools/BrushTool.cpp index 553936a8bc..b432c1842b 100644 --- a/Userland/Applications/PixelPaint/Tools/BrushTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/BrushTool.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2020, Ben Jilks * Copyright (c) 2021, Mustafa Quraish - * Copyright (c) 2022, Torsten Engelmann + * Copyright (c) 2022-2023, Torsten Engelmann * * SPDX-License-Identifier: BSD-2-Clause */ @@ -149,10 +149,10 @@ ErrorOr BrushTool::get_properties_widget() auto size_label = TRY(size_container->try_add("Size:"_string)); size_label->set_text_alignment(Gfx::TextAlignment::CenterLeft); - size_label->set_fixed_size(80, 20); + size_label->set_fixed_size(60, 20); auto size_slider = TRY(size_container->try_add(Orientation::Horizontal, "px"_string)); - size_slider->set_range(1, 100); + size_slider->set_range(1, 250); size_slider->set_value(m_size); size_slider->set_override_cursor(cursor()); @@ -169,7 +169,7 @@ ErrorOr BrushTool::get_properties_widget() auto hardness_label = TRY(hardness_container->try_add("Hardness:"_string)); hardness_label->set_text_alignment(Gfx::TextAlignment::CenterLeft); - hardness_label->set_fixed_size(80, 20); + hardness_label->set_fixed_size(60, 20); auto hardness_slider = TRY(hardness_container->try_add(Orientation::Horizontal, "%"_string)); hardness_slider->set_range(1, 100); @@ -188,19 +188,23 @@ ErrorOr BrushTool::get_properties_widget() NonnullRefPtr BrushTool::build_cursor() { m_scale_last_created_cursor = m_editor ? m_editor->scale() : 1; - auto scaled_size = size() * m_scale_last_created_cursor; - auto containing_box_size = 2 * scaled_size; + auto containing_box_size = AK::clamp(preferred_cursor_size(), 1.0f, max_allowed_cursor_size()); + auto centered = containing_box_size / 2; NonnullRefPtr new_cursor = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::IntSize(containing_box_size, containing_box_size)).release_value_but_fixme_should_propagate_errors(); Gfx::Painter painter { new_cursor }; Gfx::AntiAliasingPainter aa_painter { painter }; - painter.draw_line({ scaled_size - 5, scaled_size }, { scaled_size + 5, scaled_size }, Color::LightGray, 3); - painter.draw_line({ scaled_size, scaled_size - 5 }, { scaled_size, scaled_size + 5 }, Color::LightGray, 3); - painter.draw_line({ scaled_size - 5, scaled_size }, { scaled_size + 5, scaled_size }, Color::MidGray, 1); - painter.draw_line({ scaled_size, scaled_size - 5 }, { scaled_size, scaled_size + 5 }, Color::MidGray, 1); - aa_painter.draw_ellipse(Gfx::IntRect(0, 0, containing_box_size, containing_box_size), Color::LightGray, 1); - + painter.draw_line({ centered - 5, centered }, { centered + 5, centered }, Color::LightGray, 3); + painter.draw_line({ centered, centered - 5 }, { centered, centered + 5 }, Color::LightGray, 3); + painter.draw_line({ centered - 5, centered }, { centered + 5, centered }, Color::MidGray, 1); + painter.draw_line({ centered, centered - 5 }, { centered, centered + 5 }, Color::MidGray, 1); + if (max_allowed_cursor_size() != containing_box_size) { + aa_painter.draw_ellipse(Gfx::IntRect(0, 0, containing_box_size, containing_box_size), Color::LightGray, 1); + } else { + aa_painter.draw_ellipse(Gfx::IntRect(0, 0, containing_box_size, containing_box_size), Color::Red, 1); + aa_painter.draw_ellipse(Gfx::IntRect(3, 3, containing_box_size - 6, containing_box_size - 6), Color::LightGray, 1); + } return new_cursor; } @@ -211,4 +215,13 @@ void BrushTool::refresh_editor_cursor() m_editor->update_tool_cursor(); } +float BrushTool::preferred_cursor_size() +{ + return 2 * size() * (m_editor ? m_editor->scale() : 1); +} + +float BrushTool::max_allowed_cursor_size() +{ + return m_editor ? Gfx::IntPoint(0, 0).distance_from({ m_editor->width(), m_editor->height() }) * 1.1f : 500; +} } diff --git a/Userland/Applications/PixelPaint/Tools/BrushTool.h b/Userland/Applications/PixelPaint/Tools/BrushTool.h index adb3f84398..aab50914bc 100644 --- a/Userland/Applications/PixelPaint/Tools/BrushTool.h +++ b/Userland/Applications/PixelPaint/Tools/BrushTool.h @@ -2,7 +2,7 @@ * Copyright (c) 2020, Ben Jilks * Copyright (c) 2021, Mustafa Quraish * Copyright (c) 2022, the SerenityOS developers. - * Copyright (c) 2022, Torsten Engelmann + * Copyright (c) 2022-2023, Torsten Engelmann * * SPDX-License-Identifier: BSD-2-Clause */ @@ -50,6 +50,8 @@ protected: virtual void draw_line(Gfx::Bitmap& bitmap, Gfx::Color color, Gfx::IntPoint start, Gfx::IntPoint end); virtual NonnullRefPtr build_cursor(); void refresh_editor_cursor(); + virtual float preferred_cursor_size(); + virtual float max_allowed_cursor_size(); float m_scale_last_created_cursor = 0; private: diff --git a/Userland/Applications/PixelPaint/Tools/EraseTool.cpp b/Userland/Applications/PixelPaint/Tools/EraseTool.cpp index 9519873265..85b5a6c84d 100644 --- a/Userland/Applications/PixelPaint/Tools/EraseTool.cpp +++ b/Userland/Applications/PixelPaint/Tools/EraseTool.cpp @@ -69,7 +69,7 @@ ErrorOr EraseTool::get_properties_widget() size_label->set_fixed_size(80, 20); auto size_slider = TRY(size_container->try_add(Orientation::Horizontal, "px"_string)); - size_slider->set_range(1, 100); + size_slider->set_range(1, 250); size_slider->set_value(size()); size_slider->on_change = [this, size_slider](int value) { @@ -144,20 +144,28 @@ NonnullRefPtr EraseTool::build_cursor() return BrushTool::build_cursor(); m_scale_last_created_cursor = m_editor ? m_editor->scale() : 1; - int scaled_size = size() * m_scale_last_created_cursor; + int cursor_size = AK::clamp(preferred_cursor_size(), 1, max_allowed_cursor_size()); - NonnullRefPtr new_cursor = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::IntSize(scaled_size, scaled_size)).release_value_but_fixme_should_propagate_errors(); + NonnullRefPtr new_cursor = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::IntSize(cursor_size, cursor_size)).release_value_but_fixme_should_propagate_errors(); - Gfx::IntRect rect { 0, 0, scaled_size, scaled_size }; Gfx::Painter painter { new_cursor }; - painter.draw_rect(rect, Color::LightGray); - painter.draw_line({ scaled_size / 2 - 5, scaled_size / 2 }, { scaled_size / 2 + 5, scaled_size / 2 }, Color::LightGray, 3); - painter.draw_line({ scaled_size / 2, scaled_size / 2 - 5 }, { scaled_size / 2, scaled_size / 2 + 5 }, Color::LightGray, 3); - painter.draw_line({ scaled_size / 2 - 5, scaled_size / 2 }, { scaled_size / 2 + 5, scaled_size / 2 }, Color::MidGray, 1); - painter.draw_line({ scaled_size / 2, scaled_size / 2 - 5 }, { scaled_size / 2, scaled_size / 2 + 5 }, Color::MidGray, 1); + if (preferred_cursor_size() > max_allowed_cursor_size()) { + painter.draw_rect({ 0, 0, cursor_size, cursor_size }, Color::Red); + painter.draw_rect({ 3, 3, cursor_size - 6, cursor_size - 6 }, Color::LightGray); + } else { + painter.draw_rect({ 0, 0, cursor_size, cursor_size }, Color::LightGray); + } + painter.draw_line({ cursor_size / 2 - 5, cursor_size / 2 }, { cursor_size / 2 + 5, cursor_size / 2 }, Color::LightGray, 3); + painter.draw_line({ cursor_size / 2, cursor_size / 2 - 5 }, { cursor_size / 2, cursor_size / 2 + 5 }, Color::LightGray, 3); + painter.draw_line({ cursor_size / 2 - 5, cursor_size / 2 }, { cursor_size / 2 + 5, cursor_size / 2 }, Color::MidGray, 1); + painter.draw_line({ cursor_size / 2, cursor_size / 2 - 5 }, { cursor_size / 2, cursor_size / 2 + 5 }, Color::MidGray, 1); return new_cursor; } +float EraseTool::preferred_cursor_size() +{ + return size() * (m_editor ? m_editor->scale() : 1); +} } diff --git a/Userland/Applications/PixelPaint/Tools/EraseTool.h b/Userland/Applications/PixelPaint/Tools/EraseTool.h index a85196c080..59db17165d 100644 --- a/Userland/Applications/PixelPaint/Tools/EraseTool.h +++ b/Userland/Applications/PixelPaint/Tools/EraseTool.h @@ -26,6 +26,7 @@ protected: virtual Color color_for(GUI::MouseEvent const& event) override; virtual void draw_point(Gfx::Bitmap& bitmap, Gfx::Color color, Gfx::IntPoint point) override; virtual NonnullRefPtr build_cursor() override; + virtual float preferred_cursor_size() override; private: virtual StringView tool_name() const override { return "Erase Tool"sv; }