File indexing completed on 2024-05-12 15:56:11

0001 /*
0002  *  SPDX-FileCopyrightText: 2004 Boudewijn Rempt <boud@valdyas.org>
0003  *  SPDX-FileCopyrightText: 2005 Bart Coppens <kde@bartcoppens.be>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 #ifndef KIS_IMAGE_PIPE_BRUSH_P_H
0008 #define KIS_IMAGE_PIPE_BRUSH_P_H
0009 
0010 #include "kis_imagepipe_brush.h"
0011 #include <math.h>
0012 #include <limits.h>
0013 
0014 #include <QImage>
0015 #include <QPoint>
0016 #include <QVector>
0017 #include <QFile>
0018 #include <QRegExp>
0019 #include <QStringList>
0020 
0021 #include <kis_debug.h>
0022 #include <klocalizedstring.h>
0023 #include <krandom.h>
0024 
0025 #include "kis_global.h"
0026 #include "kis_paint_device.h"
0027 #include "kis_layer.h"
0028 
0029 #include "kritabrush_export.h"
0030 
0031 /**
0032  * The parasite info that gets loaded from the terribly documented gimp pipe brush parasite.
0033  *
0034  * We only store data we actually use.
0035  *
0036  * BC: How it seems the dimension stuff interacts with rank, selectionMode and the actual
0037  * selection of a brush to be drawn. So apparently you can have at most 4 'dimensions'.
0038  * Each dimension has a number of brushes, the rank. Each dimension has an associated selection
0039  * mode and placement mode (which we don't use). The selection mode says us in which way
0040  * which of the brushes or brush sets will be selected. In the case of a 1-dimensional pipe
0041  * brush it is easy.
0042  *
0043  * However, when there are more dimensions it is a bit harder. You can according to the gimp
0044  * source maximally use 4 dimensions. When you want to select a brush, you first go to the
0045  * first dimension. Say it has a rank of 2. The code chooses one of the 2 according to the
0046  * selection mode. Say we choose 2. Then the currentBrush will skip over all the brushes
0047  * from the first element in dimension 1. Then in dimension we pick again from the choices
0048  * we have in dimension 2. We again add the appropriate amount to currentBrush. And so on,
0049  * until we have reached dimension dim. Or at least, that is how it looks like, we'll know
0050  * for sure when we can test it better with >1 dim brushes and Angular selectionMode.
0051  **/
0052 class BRUSH_EXPORT KisPipeBrushParasite
0053 {
0054 public:
0055     /// Set some default values
0056     KisPipeBrushParasite()
0057         : ncells(0)
0058         , dim(0)
0059         , needsMovement(false) {
0060         init();
0061     }
0062 
0063     void init();
0064     void sanitize();
0065 
0066     /// Initializes the brushesCount helper
0067     void setBrushesCount();
0068 
0069     /// Load the parasite from the source string
0070     KisPipeBrushParasite(const QString& source);
0071 
0072     /**
0073      * Saves a GIMP-compatible representation of this parasite to the device. Also writes the
0074      * number of brushes (== ncells) (no trailing '\n') */
0075     bool saveToDevice(QIODevice* dev) const;
0076     bool loadFromDevice(QIODevice *dev);
0077 
0078     enum Placement { DefaultPlacement, ConstantPlacement, RandomPlacement };
0079 
0080     static int const MaxDim = 4;
0081 
0082     //qint32 step;
0083     qint32 ncells {0};
0084     qint32 dim {0};
0085 
0086     // Apparently only used for editing a pipe brush, which we won't at the moment
0087     // qint32 cols, rows;
0088     // qint32 cellwidth, cellheight;
0089     // Apparently the gimp doesn't use this anymore? Anyway it is a bit weird to
0090     // paint at someplace else than where your cursor displays it will...
0091     //Placement placement;
0092     qint32 rank[MaxDim] {};
0093 
0094     KisParasite::SelectionMode selection[MaxDim];
0095     QString selectionMode; // for UI
0096 
0097     /// The total count of brushes in each dimension (helper)
0098     qint32 brushesCount[MaxDim];
0099 
0100     /// The current index in each dimension, so that the selection modes know where to start
0101     qint32 index[MaxDim];
0102 
0103     /// If true, the brush won't be painted when there is no motion
0104     bool needsMovement {false};
0105 };
0106 #endif