/* * 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 //#define PAINT_DEBUG namespace PixelPaint { RefPtr Image::create_with_size(const Gfx::IntSize& 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::IntSize& size) : m_size(size) { } void Image::paint_into(GUI::Painter& painter, const Gfx::IntRect& dest_rect) { float scale = (float)dest_rect.width() / (float)rect().width(); Gfx::PainterStateSaver saver(painter); painter.add_clip_rect(dest_rect); for (auto& layer : m_layers) { if (!layer.is_visible()) continue; auto target = dest_rect.translated(layer.location().x() * scale, layer.location().y() * scale); target.set_size(layer.size().width() * scale, layer.size().height() * scale); painter.draw_scaled_bitmap(target, layer.bitmap(), layer.rect(), (float)layer.opacity_percent() / 100.0f); } } void Image::add_layer(NonnullRefPtr layer) { for (auto& existing_layer : m_layers) { ASSERT(&existing_layer != layer.ptr()); } m_layers.append(move(layer)); for (auto* client : m_clients) client->image_did_add_layer(m_layers.size() - 1); did_modify_layer_stack(); } size_t Image::index_of(const Layer& layer) const { for (size_t i = 0; i < m_layers.size(); ++i) { if (&m_layers.at(i) == &layer) return i; } ASSERT_NOT_REACHED(); } void Image::move_layer_to_back(Layer& layer) { NonnullRefPtr protector(layer); auto index = index_of(layer); m_layers.remove(index); m_layers.prepend(layer); did_modify_layer_stack(); } void Image::move_layer_to_front(Layer& layer) { NonnullRefPtr protector(layer); auto index = index_of(layer); m_layers.remove(index); m_layers.append(layer); did_modify_layer_stack(); } void Image::move_layer_down(Layer& layer) { NonnullRefPtr protector(layer); auto index = index_of(layer); if (!index) return; m_layers.remove(index); m_layers.insert(index - 1, layer); did_modify_layer_stack(); } void Image::move_layer_up(Layer& layer) { NonnullRefPtr protector(layer); auto index = index_of(layer); if (index == m_layers.size() - 1) return; m_layers.remove(index); m_layers.insert(index + 1, layer); did_modify_layer_stack(); } void Image::change_layer_index(size_t old_index, size_t new_index) { ASSERT(old_index < m_layers.size()); ASSERT(new_index < m_layers.size()); auto layer = m_layers.take(old_index); m_layers.insert(new_index, move(layer)); did_modify_layer_stack(); } void Image::did_modify_layer_stack() { for (auto* client : m_clients) client->image_did_modify_layer_stack(); did_change(); } void Image::remove_layer(Layer& layer) { NonnullRefPtr protector(layer); auto index = index_of(layer); m_layers.remove(index); for (auto* client : m_clients) client->image_did_remove_layer(index); did_modify_layer_stack(); } void Image::add_client(ImageClient& client) { ASSERT(!m_clients.contains(&client)); m_clients.set(&client); } void Image::remove_client(ImageClient& client) { ASSERT(m_clients.contains(&client)); m_clients.remove(&client); } void Image::layer_did_modify_bitmap(Badge, const Layer& layer) { auto layer_index = index_of(layer); for (auto* client : m_clients) client->image_did_modify_layer(layer_index); did_change(); } void Image::layer_did_modify_properties(Badge, const Layer& layer) { auto layer_index = index_of(layer); for (auto* client : m_clients) client->image_did_modify_layer(layer_index); did_change(); } void Image::did_change() { for (auto* client : m_clients) client->image_did_change(); } }