/* * Copyright 2017 Laszlo Balazs-Csiki * * This file is part of Pixelitor. Pixelitor is free software: you * can redistribute it and/or modify it under the terms of the GNU * General Public License, version 3 as published by the Free * Software Foundation. * * Pixelitor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Pixelitor. If not, see <http://www.gnu.org/licenses/>. */ package pixelitor.layers; import pixelitor.Composition; import pixelitor.filters.comp.Flip; import pixelitor.filters.comp.Rotate; import pixelitor.filters.painters.TextAdjustmentsPanel; import pixelitor.filters.painters.TextSettings; import pixelitor.filters.painters.TranslatedTextPainter; import pixelitor.gui.ImageComponents; import pixelitor.gui.PixelitorWindow; import pixelitor.gui.utils.OKCancelDialog; import pixelitor.history.ContentLayerMoveEdit; import pixelitor.history.History; import pixelitor.history.NewLayerEdit; import pixelitor.history.TextLayerChangeEdit; import pixelitor.history.TextLayerRasterizeEdit; import pixelitor.utils.ImageUtils; import pixelitor.utils.Utils; import pixelitor.utils.test.RandomGUITest; import java.awt.Graphics2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.ObjectInputStream; /** * A text layer */ public class TextLayer extends ContentLayer { private static final long serialVersionUID = 2L; private final TranslatedTextPainter painter; private TextSettings settings; public TextLayer(Composition comp) { this(comp, ""); } public TextLayer(Composition comp, String name) { super(comp, name, null); painter = new TranslatedTextPainter(); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); isAdjustment = settings.isWatermark(); } @Override public void paintLayerOnGraphics(Graphics2D g, boolean firstVisibleLayer) { painter.setFillPaint(settings.getColor()); painter.paint(g, null, comp.getCanvasWidth(), comp.getCanvasHeight()); } @Override public BufferedImage applyLayer(Graphics2D g, boolean firstVisibleLayer, BufferedImage imageSoFar) { if (settings == null) { // the layer was just created, nothing to paint yet return imageSoFar; } // the text will be painted normally return super.applyLayer(g, firstVisibleLayer, imageSoFar); } @Override public BufferedImage adjustImage(BufferedImage src) { assert settings.isWatermark(); // should be called only in this case return settings.watermarkImage(src, painter); } public BufferedImage createRasterizedImage() { BufferedImage img = ImageUtils.createSysCompatibleImage(canvas.getWidth(), canvas.getHeight()); Graphics2D g = img.createGraphics(); applyLayer(g, true, img); g.dispose(); return img; } @Override public Layer duplicate(boolean sameName) { String duplicateName = sameName ? name : Utils.createCopyName(name); TextLayer d = new TextLayer(comp, duplicateName); d.translationX = translationX; d.translationY = translationY; d.painter.setTranslation( painter.getTX(), painter.getTY()); d.setSettings(new TextSettings(settings)); if (hasMask()) { d.addMask(mask.duplicate(d)); } return d; } @Override public void moveWhileDragging(double x, double y) { super.moveWhileDragging(x, y); painter.setTranslation(getTX(), getTY()); } @Override ContentLayerMoveEdit createMovementEdit(int oldTX, int oldTY) { return new ContentLayerMoveEdit(this, null, oldTX, oldTY); } @Override public void setTranslation(int x, int y) { super.setTranslation(x, y); painter.setTranslation(x, y); } public void setSettings(TextSettings settings) { this.settings = settings; isAdjustment = settings.isWatermark(); settings.configurePainter(painter); } public TextSettings getSettings() { return settings; } public void updateLayerName() { if (settings != null) { setName(settings.getText(), false); } } public void edit(PixelitorWindow pw) { if (RandomGUITest.isRunning()) { return; // avoid dialogs } TextSettings oldSettings = getSettings(); TextAdjustmentsPanel p = new TextAdjustmentsPanel(this); OKCancelDialog d = new OKCancelDialog(p, pw, "Edit Text Layer") { @Override protected void dialogAccepted() { close(); commitSettings(oldSettings); } @Override protected void dialogCanceled() { close(); setSettings(oldSettings); comp.imageChanged(Composition.ImageChangeActions.FULL); } }; d.setVisible(true); } public void commitSettings(TextSettings oldSettings) { updateLayerName(); TextLayerChangeEdit edit = new TextLayerChangeEdit( comp, this, oldSettings ); History.addEdit(edit); } ///// from here static utility methods public static void createNew(PixelitorWindow pw) { Composition comp = ImageComponents.getActiveCompOrNull(); if (comp == null) { // TODO dialog? return; } TextLayer textLayer = new TextLayer(comp); Layer activeLayerBefore = comp.getActiveLayer(); MaskViewMode oldViewMode = comp.getIC().getMaskViewMode(); // don't add it yet to history, only after the user chooses to press OK comp.addLayer(textLayer, false, null, true, false); TextAdjustmentsPanel p = new TextAdjustmentsPanel(textLayer); OKCancelDialog d = new OKCancelDialog(p, pw, "Create Text Layer") { @Override protected void dialogAccepted() { close(); textLayer.updateLayerName(); // now it is safe to add it to the history NewLayerEdit newLayerEdit = new NewLayerEdit(comp, textLayer, activeLayerBefore, "New Text Layer", oldViewMode); History.addEdit(newLayerEdit); } @Override protected void dialogCanceled() { close(); comp.deleteLayer(textLayer, false, true); } }; d.setVisible(true); } public ImageLayer replaceWithRasterized() { BufferedImage rasterizedImage = createRasterizedImage(); ImageLayer newImageLayer = new ImageLayer(comp, rasterizedImage, getName(), null); comp.addLayer(newImageLayer, false, null, false, false); comp.deleteLayer(this, false, true); TextLayerRasterizeEdit edit = new TextLayerRasterizeEdit(comp, this, newImageLayer); History.addEdit(edit); return newImageLayer; } @Override public void enlargeCanvas(int north, int east, int south, int west) { // TODO } @Override public void flip(Flip.Direction direction) { // TODO } @Override public void rotate(Rotate.SpecialAngle angle) { // TODO } @Override public void resize(int targetWidth, int targetHeight, boolean progressiveBilinear) { // TODO } @Override public void crop(Rectangle2D cropRect) { // Rectangle textBounds = painter.getTextBounds(); // int currentX = textBounds.x; // int currentY = textBounds.y; // int newX = currentX - selectionBounds.x; // int newY = currentY - selectionBounds.y; // TODO this still doesn't work probably because // the alignment has not been taken into account // setTranslationX(getTX() - selectionBounds.x); // setTranslationY(getTY() - selectionBounds.y); } @Override public String toString() { return getClass().getSimpleName() + "{text=" + (settings == null ? "null settings" : settings.getText()) + ", super=" + super.toString() + '}'; } }