File indexing completed on 2024-06-23 04:19:02

0001 
0002 /*
0003    Copyright (c) 2003-2007 Clarence Dang <dang@kde.org>
0004    All rights reserved.
0005 
0006    Redistribution and use in source and binary forms, with or without
0007    modification, are permitted provided that the following conditions
0008    are met:
0009 
0010    1. Redistributions of source code must retain the above copyright
0011       notice, this list of conditions and the following disclaimer.
0012    2. Redistributions in binary form must reproduce the above copyright
0013       notice, this list of conditions and the following disclaimer in the
0014       documentation and/or other materials provided with the distribution.
0015 
0016    THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0017    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0018    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0019    IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0020    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0021    NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0022    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0023    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0024    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0025    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0026 */
0027 
0028 
0029 #ifndef kpTextSelection_H
0030 #define kpTextSelection_H
0031 
0032 
0033 #include "layers/selections/kpAbstractSelection.h"
0034 #include "imagelib/kpImage.h"
0035 #include "layers/selections/text/kpTextStyle.h"
0036 #include "layers/selections/text/kpPreeditText.h"
0037 
0038 //
0039 // A rectangular text box containing lines of text, rendered in a given text
0040 // style.
0041 //
0042 // A text selection with an empty list of text lines is just a text box
0043 // border and contains no content.
0044 //
0045 // The minimal text selection that is considered to contain content consists
0046 // of a single empty text line.
0047 //
0048 // The rendered elements are as follows:
0049 //
0050 //     ###############
0051 //     #             #
0052 //     #    *        *---------- Text Border
0053 //     #    |        #
0054 //     #####|#########
0055 //          |
0056 //          |
0057 //       Text Area
0058 //       (text lines are rendered on top of here; the parts of the lines
0059 //        that don't fit here are not rendered)
0060 //
0061 // The text style determines how the text box is drawn.
0062 //
0063 // The foreground color determines the color of the text.  Transparent
0064 // foreground text means that the text box is see-through for the pixels
0065 // of the text, exposing the document pixels below.  It does not mean
0066 // that the transparent color is drawn onto the document.  In other
0067 // words, we are "painting" transparent pixels -- not "setting" them.
0068 //
0069 // If the background color is opaque, the text is drawn on top of a
0070 // filled-in rectangle and the rectangle completely overwrites any
0071 // document pixels below.
0072 //
0073 // Consistent with the behavior of a transparent foreground color, a
0074 // transparent background color does not mean that a transparent-colored
0075 // rectangle is drawn onto the document.  Instead, it means that the
0076 // text box background is see-through so that text is drawn directly on
0077 // top of the document pixels.  No rectangle is drawn in this case.
0078 //
0079 // A text box with transparent foreground and background colors is
0080 // completely invisible since both the text and background are see-through.
0081 //
0082 // A rendered text cursor is controlled separately by kpViewManager, as
0083 // cursors are only a view concept so do not belong in this document-based
0084 // class.
0085 //
0086 // Marshalling, for copying text selections to the clipboard, is not
0087 // currently supported.  This is because generally, users are only interested
0088 // in the text itself, not the border nor formatting.
0089 //
0090 class kpTextSelection : public kpAbstractSelection
0091 {
0092 Q_OBJECT
0093 
0094 //
0095 // Initialization
0096 //
0097 
0098 public:
0099     explicit kpTextSelection (const QRect &rect = QRect (),
0100         const kpTextStyle &textStyle = kpTextStyle ());
0101     kpTextSelection (const QRect &rect, const QList <QString> &textLines,
0102         const kpTextStyle &textStyle);
0103     kpTextSelection (const kpTextSelection &rhs);
0104 
0105     kpTextSelection &operator= (const kpTextSelection &rhs);
0106 
0107     kpTextSelection *clone () const override;
0108 
0109     // Returns a copy of the text selection but with new dimensions
0110     // <newWidth> x <newHeight>.
0111     kpTextSelection *resized (int newWidth, int newHeight) const;
0112 
0113     ~kpTextSelection () override;
0114 
0115 
0116 //
0117 // Marshalling
0118 //
0119 
0120 public:
0121     int serialID () const override;
0122 
0123     bool readFromStream (QDataStream &stream) override;
0124 
0125     void writeToStream (QDataStream &stream) const override;
0126 
0127 
0128 //
0129 // General Queries
0130 //
0131 
0132 public:
0133     QString name () const override;
0134 
0135     kpCommandSize::SizeType size () const override;
0136 
0137 public:
0138     bool isRectangular () const override;
0139 
0140 
0141 //
0142 // Position & Dimensions
0143 //
0144 
0145 public:
0146     // Returns the absolute minimum size that a textbox must be if it is of
0147     // the given <textStyle>.
0148     //
0149     // This leaves enough room for the border on all 4 sides and also a
0150     // text area big enough to fit a character in an extremely small font.
0151     static int MinimumWidthForTextStyle (const kpTextStyle &textStyle);
0152     static int MinimumHeightForTextStyle (const kpTextStyle &textStyle);
0153     static QSize MinimumSizeForTextStyle (const kpTextStyle &textStyle);
0154 
0155     // REFACTOR: Enforce in kpTextSelection, not just in kpToolSelection &
0156     //           when pasting (in kpMainWindow).
0157     //
0158     //           Otherwise, if enforcement fails, e.g. textAreaRect() will
0159     //           not work.
0160     int minimumWidth () const override;
0161     int minimumHeight () const override;
0162 
0163 public:
0164     // Returns the suggested minimum size that a textbox should be if it is of
0165     // the given <textStyle>.
0166     //
0167     // This leaves enough room for the border on all 4 sides and also for
0168     // a small line of the text in the given text style.
0169     static int PreferredMinimumWidthForTextStyle (const kpTextStyle &textStyle);
0170     static int PreferredMinimumHeightForTextStyle (const kpTextStyle &textStyle);
0171     static QSize PreferredMinimumSizeForTextStyle (const kpTextStyle &textStyle);
0172 
0173 public:
0174     // Returns the size of the text border.  Constant.
0175     static int TextBorderSize ();
0176 
0177     // Returns the rectangle that text lines are drawn on top of.
0178     // This will be a sub-rectangle of boundingRect() and is therefore,
0179     // in document coordinates like everything else in this class.
0180     QRect textAreaRect () const;
0181 
0182 public:
0183     QPolygon calculatePoints () const override;
0184 
0185 
0186 //
0187 // Point Testing
0188 //
0189 
0190 public:
0191     bool contains (const QPoint &point) const override;
0192 
0193 public:
0194     bool pointIsInTextBorderArea (const QPoint &point) const;
0195     bool pointIsInTextArea (const QPoint &point) const;
0196 
0197 
0198 //
0199 // Content
0200 //
0201 
0202 public:
0203     // (see class header comment)
0204     bool hasContent () const override;
0205 
0206     void deleteContent () override;
0207 
0208 public:
0209     QList <QString> textLines () const;
0210     void setTextLines (const QList <QString> &textLines);
0211 
0212     static QString textForTextLines (const QList <QString> &textLines);
0213     // Returns textLines() as one long newline-separated string.
0214     // If the last text line is not empty, there is no trailing newline.
0215     QString text () const;
0216 
0217 
0218 //
0219 // Text Style
0220 //
0221 
0222 public:
0223     kpTextStyle textStyle () const;
0224     void setTextStyle (const kpTextStyle &textStyle);
0225 
0226 
0227 //
0228 // Preedit Text
0229 //
0230 
0231 public:
0232     kpPreeditText preeditText () const;
0233     void setPreeditText (const kpPreeditText &preeditText);
0234 
0235 //
0236 // Cursor
0237 //
0238 // A text cursor position is the row and column of a character in
0239 // textLines(), that it is to the left of.  As a result, a column value
0240 // of 1 character past the last character of a text line is allowed.
0241 //
0242 
0243 public:
0244     // If the given point is in the text area, it returns the closest
0245     // row/column (in textLines()) for the point.
0246     //
0247     // If the given point is not in the text area, it returns -1.
0248     int closestTextRowForPoint (const QPoint &point) const;
0249     int closestTextColForPoint (const QPoint &point) const;
0250 
0251     // Given a valid row and column in textLines(), returns the top-left
0252     // point of where the text cursor should be rendered.
0253     // TODO: Code is not symmetric to closestTest{Row,Col}ForPoint()
0254     //       [look at the Y/row value calculations]
0255     //
0256     // If the row and column is not inside textLines(), it returns
0257     // KP_INVALID_POINT.
0258     QPoint pointForTextRowCol (int row, int col) const;
0259 
0260 
0261 //
0262 // Rendering
0263 //
0264 
0265 private:
0266     void drawPreeditString(QPainter &painter, int &x, int y, const kpPreeditText &preeditText) const;
0267 
0268 public:
0269     void paint(QImage *destPixmap, const QRect &docRect) const override;
0270 
0271     void paintBorder(QImage *destPixmap, const QRect &docRect,
0272                              bool selectionFinished) const override;
0273 
0274 public:
0275     // Returns an image that contains the painted text (without a border).
0276     //
0277     // If the text box has a see-through background, the image will be given
0278     // an arbitrarily neutral background (currently, the transparent color).
0279     // As a result, the returned image will be an approximation since text
0280     // boxes are normally rendered -- and antialiased with -- a different
0281     // background, namely the document image.  Therefore, it is invalid to
0282     // stamp the returned image onto the document image and expect it to look
0283     // like stamping this text selection onto the document image (the latter
0284     // is achieved via kpDocument::selectionPushOntoDocument(), antialiases
0285     // and is more correct).
0286     kpImage approximateImage () const;
0287 
0288 
0289 private:
0290     struct kpTextSelectionPrivate * const d;
0291 };
0292 
0293 
0294 #endif  // kpTextSelection_H