diff --git a/Applications/PaintBrush/Image.cpp b/Applications/PaintBrush/Image.cpp new file mode 100644 index 0000000000..63861acf23 --- /dev/null +++ b/Applications/PaintBrush/Image.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 "Layer.h" +#include + +namespace PaintBrush { + +RefPtr Image::create_with_size(const Gfx::Size& size) +{ + if (size.is_empty()) + return nullptr; + + if (size.width() > 16384 || size.height() > 16384) + return nullptr; + + return adopt(*new Image(size)); +} + +Image::Image(const Gfx::Size& size) + : m_size(size) +{ +} + +void Image::paint_into(GUI::Painter& painter, const Gfx::Rect& dest_rect, const Gfx::Rect& src_rect) +{ + for (auto& layer : m_layers) { + auto target = dest_rect.translated(layer.location()); + dbg() << "Composite layer " << layer.name() << " target: " << target << ", src_rect: " << src_rect; + painter.draw_scaled_bitmap(target, layer.bitmap(), src_rect); + } +} + +void Image::add_layer(NonnullRefPtr layer) +{ + for (auto& existing_layer : m_layers) { + ASSERT(&existing_layer != layer.ptr()); + } + m_layers.append(move(layer)); +} + +} diff --git a/Applications/PaintBrush/Image.h b/Applications/PaintBrush/Image.h new file mode 100644 index 0000000000..76f4cbe188 --- /dev/null +++ b/Applications/PaintBrush/Image.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 +#include +#include +#include +#include +#include + +namespace PaintBrush { + +class Layer; + +class Image : public RefCounted { +public: + static RefPtr create_with_size(const Gfx::Size&); + + size_t layer_count() const { return m_layers.size(); } + const Layer& layer(size_t index) const { return m_layers.at(index); } + + const Gfx::Size& size() const { return m_size; } + Gfx::Rect rect() const { return { {}, m_size }; } + + void add_layer(NonnullRefPtr); + + void paint_into(GUI::Painter&, const Gfx::Rect& dest_rect, const Gfx::Rect& src_rect); + +private: + explicit Image(const Gfx::Size&); + + Gfx::Size m_size; + NonnullRefPtrVector m_layers; +}; + +} diff --git a/Applications/PaintBrush/ImageEditor.cpp b/Applications/PaintBrush/ImageEditor.cpp new file mode 100644 index 0000000000..76b052e730 --- /dev/null +++ b/Applications/PaintBrush/ImageEditor.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 "ImageEditor.h" +#include "Image.h" +#include "Layer.h" +#include +#include + +namespace PaintBrush { + +ImageEditor::ImageEditor() +{ +} + +void ImageEditor::set_image(RefPtr image) +{ + m_image = move(image); + update(); +} + +void ImageEditor::paint_event(GUI::PaintEvent& event) +{ + GUI::Frame::paint_event(event); + + GUI::Painter painter(*this); + painter.add_clip_rect(event.rect()); + + painter.fill_rect_with_checkerboard(rect(), { 8, 8 }, palette().base().darkened(0.9), palette().base()); + + if (m_image) { + m_image->paint_into(painter, m_image->rect(), m_image->rect()); + } +} + +} diff --git a/Applications/PaintBrush/ImageEditor.h b/Applications/PaintBrush/ImageEditor.h new file mode 100644 index 0000000000..0e3869ee8e --- /dev/null +++ b/Applications/PaintBrush/ImageEditor.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 + +namespace PaintBrush { + +class Image; + +class ImageEditor final : public GUI::Frame { + C_OBJECT(ImageEditor); + +public: + const Image* image() const { return m_image; } + Image* image() { return m_image; } + + void set_image(RefPtr); + +private: + ImageEditor(); + + virtual void paint_event(GUI::PaintEvent&) override; + + RefPtr m_image; +}; + +} diff --git a/Applications/PaintBrush/Layer.cpp b/Applications/PaintBrush/Layer.cpp new file mode 100644 index 0000000000..73737d486e --- /dev/null +++ b/Applications/PaintBrush/Layer.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 "Layer.h" +#include + +namespace PaintBrush { + +RefPtr Layer::create_with_size(const Gfx::Size& size, const String& name) +{ + if (size.is_empty()) + return nullptr; + + if (size.width() > 16384 || size.height() > 16384) + return nullptr; + + return adopt(*new Layer(size, name)); +} + +Layer::Layer(const Gfx::Size& size, const String& name) + : m_name(name) +{ + m_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA32, size); +} + +} diff --git a/Applications/PaintBrush/Layer.h b/Applications/PaintBrush/Layer.h new file mode 100644 index 0000000000..38188090d1 --- /dev/null +++ b/Applications/PaintBrush/Layer.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 +#include +#include + +namespace PaintBrush { + +class Layer : public RefCounted { + AK_MAKE_NONCOPYABLE(Layer); + AK_MAKE_NONMOVABLE(Layer); + +public: + static RefPtr create_with_size(const Gfx::Size&, const String& name); + + ~Layer() {} + + const Gfx::Point& location() const { return m_location; } + void set_location(const Gfx::Point& location) { m_location = location; } + + const Gfx::Bitmap& bitmap() const { return *m_bitmap; } + Gfx::Bitmap& bitmap() { return *m_bitmap; } + Gfx::Size size() const { return bitmap().size(); } + + const String& name() const { return m_name; } + void set_name(const String& name) { m_name = name; } + +private: + explicit Layer(const Gfx::Size&, const String& name); + + String m_name; + Gfx::Point m_location; + RefPtr m_bitmap; +}; + +} diff --git a/Applications/PaintBrush/Makefile b/Applications/PaintBrush/Makefile index 9a055bd2c1..37d2ece633 100644 --- a/Applications/PaintBrush/Makefile +++ b/Applications/PaintBrush/Makefile @@ -1,16 +1,19 @@ OBJS = \ - PaintableWidget.o \ - PaletteWidget.o \ - ToolboxWidget.o \ - Tool.o \ - PenTool.o \ - LineTool.o \ - RectangleTool.o \ + BucketTool.o \ EllipseTool.o \ EraseTool.o \ - BucketTool.o \ - SprayTool.o \ + Image.o \ + ImageEditor.o \ + Layer.o \ + LineTool.o \ + PaintableWidget.o \ + PaletteWidget.o \ + PenTool.o \ PickerTool.o \ + RectangleTool.o \ + SprayTool.o \ + Tool.o \ + ToolboxWidget.o \ main.o PROGRAM = PaintBrush diff --git a/Applications/PaintBrush/main.cpp b/Applications/PaintBrush/main.cpp index c4d6cffb85..94ce7af217 100644 --- a/Applications/PaintBrush/main.cpp +++ b/Applications/PaintBrush/main.cpp @@ -24,6 +24,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "Image.h" +#include "ImageEditor.h" +#include "Layer.h" #include "PaintableWidget.h" #include "PaletteWidget.h" #include "ToolboxWidget.h" @@ -68,8 +71,12 @@ int main(int argc, char** argv) vertical_container.set_layout(); vertical_container.layout()->set_spacing(0); + auto& image_editor = vertical_container.add(); + image_editor.set_focus(true); + auto& paintable_widget = vertical_container.add(); - paintable_widget.set_focus(true); + paintable_widget.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); + paintable_widget.set_preferred_size(0, 0); vertical_container.add(paintable_widget); window->show(); @@ -105,5 +112,23 @@ int main(int argc, char** argv) app.set_menubar(move(menubar)); + auto image = PaintBrush::Image::create_with_size({ 640, 480 }); + + auto bg_layer = PaintBrush::Layer::create_with_size({ 640, 480 }, "Background"); + image->add_layer(*bg_layer); + bg_layer->bitmap().fill(Color::Magenta); + + auto fg_layer_1 = PaintBrush::Layer::create_with_size({ 200, 100 }, "Foreground 1"); + image->add_layer(*fg_layer_1); + fg_layer_1->set_location({ 20, 10 }); + fg_layer_1->bitmap().fill(Color::Green); + + auto fg_layer_2 = PaintBrush::Layer::create_with_size({ 64, 64 }, "Foreground 2"); + image->add_layer(*fg_layer_2); + fg_layer_2->set_location({ 300, 350 }); + fg_layer_2->bitmap().fill(Color::Yellow); + + image_editor.set_image(image); + return app.exec(); }