File indexing completed on 2024-04-28 05:46:49

0001 /*****************************************************************************
0002  *   Copyright 2003 - 2010 Craig Drummond <craig.p.drummond@gmail.com>       *
0003  *   Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com>                     *
0004  *                                                                           *
0005  *   This program is free software; you can redistribute it and/or modify    *
0006  *   it under the terms of the GNU Lesser General Public License as          *
0007  *   published by the Free Software Foundation; either version 2.1 of the    *
0008  *   License, or (at your option) version 3, or any later version accepted   *
0009  *   by the membership of KDE e.V. (or its successor approved by the         *
0010  *   membership of KDE e.V.), which shall act as a proxy defined in          *
0011  *   Section 6 of version 3 of the license.                                  *
0012  *                                                                           *
0013  *   This program is distributed in the hope that it will be useful,         *
0014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
0015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       *
0016  *   Lesser General Public License for more details.                         *
0017  *                                                                           *
0018  *   You should have received a copy of the GNU Lesser General Public        *
0019  *   License along with this library. If not,                                *
0020  *   see <http://www.gnu.org/licenses/>.                                     *
0021  *****************************************************************************/
0022 
0023 #ifndef __QTC_CAIRO_UTILS_H__
0024 #define __QTC_CAIRO_UTILS_H__
0025 
0026 #include <qtcurve-utils/utils.h>
0027 #include <qtcurve-utils/options.h>
0028 #include <cairo.h>
0029 
0030 #ifdef QTC_UTILS_GTK
0031 #include <gdk/gdk.h>
0032 #endif
0033 
0034 struct _GdkPoint;
0035 struct _GdkColor;
0036 // cairo_rectangle_int_t is toooo long...
0037 typedef cairo_rectangle_int_t QtcRect;
0038 /**
0039  * Construct a QtcRect
0040  */
0041 #define qtcRect(x, y, w, h) ((QtcRect){(x), (y), (w), (h)})
0042 
0043 namespace QtCurve {
0044 namespace Rect {
0045 
0046 /**
0047  * \param a a QtcRect
0048  * \param b a QtcRect
0049  *
0050  * Test if rectangle \param a and rectangle \param b are equal.
0051  */
0052 QTC_ALWAYS_INLINE static inline bool
0053 equal(const QtcRect &a, const QtcRect &b)
0054 {
0055     return (a.x == b.x && a.y == b.y && a.width == b.width &&
0056             a.height == b.height);
0057 }
0058 
0059 /**
0060  * \param src1 a QtcRect
0061  * \param src2 a QtcRect
0062  * \param[out] dest return location for the union
0063  *                  of \param src1 and \param src2
0064  *
0065  * Calculates the union of two rectangles.
0066  * The union of rectangles \param src1 and \param src2 is the smallest
0067  * rectangle which includes both \param src1 and \param src2 within it.
0068  * It is allowed for \param dest to be the same as either
0069  * \param src1 or \param src2.
0070  * \sa gdk_rectangle_union
0071  */
0072 void union_(const QtcRect *src1, const QtcRect *src2, QtcRect *dest);
0073 
0074 /**
0075  * \param src1 a QtcRect
0076  * \param src2 a QtcRect
0077  * \param[out] dest return location for the intersection of \param src1 and
0078  *                  \param src2, or NULL
0079  *
0080  * Calculates the intersection of two rectangles. It is allowed for
0081  * \param dest to be the same as either \param src1 or \param src2.
0082  * If the rectangles do not intersect, \param dest's width and height is set
0083  * to 0 and its x and y values are undefined. If you are only interested in
0084  * whether the rectangles intersect, but not in the intersecting area itself,
0085  * pass %NULL for \param dest.
0086  *
0087  * \return true if the rectangles intersect.
0088  * \sa gdk_rectangle_intersect
0089  */
0090 bool intersect(const QtcRect *src1, const QtcRect *src2, QtcRect *dest);
0091 
0092 /**
0093  * \param rect a QtcRect
0094  * \param con a QtcRect
0095  *
0096  * Constrain \param to be the part within \param con.
0097  * \sa qtcRectIntersect
0098  */
0099 QTC_ALWAYS_INLINE static inline void
0100 constrain(QtcRect *_rect, const QtcRect *con)
0101 {
0102     intersect(_rect, con, _rect);
0103 }
0104 
0105 }
0106 
0107 namespace Cairo {
0108 
0109 class Saver {
0110     Saver(const Saver&) = delete;
0111 public:
0112     inline
0113     Saver(cairo_t *cr)
0114         : m_cr(cr),
0115           m_restored(true)
0116     {
0117         save();
0118     }
0119     inline void
0120     restore()
0121     {
0122         // not thread safe but we don't care...
0123         if (!m_restored) {
0124             m_restored = true;
0125             cairo_restore(m_cr);
0126         }
0127     }
0128     inline void
0129     save()
0130     {
0131         // not thread safe but we don't care...
0132         if (m_restored) {
0133             m_restored = false;
0134             cairo_save(m_cr);
0135         }
0136     }
0137     inline void
0138     resave()
0139     {
0140         // not thread safe but we don't care...
0141         if (!m_restored) {
0142             restore();
0143             save();
0144         }
0145     }
0146     inline
0147     ~Saver()
0148     {
0149         restore();
0150     }
0151 private:
0152     cairo_t *const m_cr;
0153     bool m_restored;
0154 };
0155 
0156 /**
0157  * \param cr a cairo_t
0158  * \param pts an array of GdkPoint
0159  * \param count the number of points in \param pts
0160  *
0161  * Add points in \param pts to the current path of \param cr.
0162  * The path is shifted by (0.5, 0.5) so that it is in the middle of the pixel.
0163  */
0164 void pathPoints(cairo_t *cr, const _GdkPoint *pts, int count);
0165 
0166 /**
0167  * \param cr a cairo_t
0168  * \param region a cairo_region_t
0169  *
0170  * Clip \param cr on \param region. The current path of \param cr will
0171  * be cleared.
0172  */
0173 void clipRegion(cairo_t *cr, const cairo_region_t *region);
0174 
0175 /**
0176  * \param cr a cairo_t
0177  * \param rect a QtcRect
0178  *
0179  * Clip \param cr on \param rect. The current path of \param cr will
0180  * be cleared.
0181  */
0182 void clipRect(cairo_t *cr, const QtcRect *_rect);
0183 
0184 /**
0185  * \param cr a cairo_t
0186  * \param col the color to be set
0187  * \param a (optional) the opacity of the color in the range [0.0 .. 1.0]
0188  *          (default: 1).
0189  *
0190  * Set the source of \param cr to \param col with opacity \param a
0191  * \sa cairo_set_source_rgba
0192  */
0193 void setColor(cairo_t *cr, const _GdkColor *col, double a=1);
0194 
0195 /**
0196  * \param pt a cairo_pattern_t
0197  * \param offset an offset in the range [0.0 .. 1.0]
0198  * \param col the color to be added.
0199  * \param a (optional) the opacity of the color in the range [0.0 .. 1.0]
0200  *          (default: 1).
0201  *
0202  * Adds a color stop with color \param col and opacity \param a to
0203  * a gradient pattern at \param offset.
0204  * \sa cairo_pattern_add_color_stop_rgba
0205  */
0206 void patternAddColorStop(cairo_pattern_t *pt, double offset,
0207                          const _GdkColor *col, double a=1);
0208 
0209 void pathTopLeft(cairo_t *cr, double xd, double yd, double width,
0210                  double height, double radius, ECornerBits round);
0211 void pathBottomRight(cairo_t *cr, double xd, double yd, double width,
0212                      double height, double radius, ECornerBits round);
0213 void pathWhole(cairo_t *cr, double xd, double yd, double width,
0214                double height, double radius, ECornerBits round);
0215 
0216 QTC_ALWAYS_INLINE static inline void
0217 clipWhole(cairo_t *cr, double x, double y, int w, int h,
0218           double radius, ECornerBits round)
0219 {
0220     cairo_new_path(cr);
0221     pathWhole(cr, x, y, w, h, radius, round);
0222     cairo_clip(cr);
0223 }
0224 
0225 #ifdef QTC_UTILS_GTK
0226 QTC_ALWAYS_INLINE static inline cairo_t*
0227 gdkCreateClip(GdkWindow *window, const QtcRect *area, double width=1)
0228 {
0229     cairo_t *cr = gdk_cairo_create(window);
0230     clipRect(cr, area);
0231     cairo_set_line_width(cr, width);
0232     return cr;
0233 }
0234 
0235 QTC_ALWAYS_INLINE static inline cairo_t*
0236 gdkCreateClip(GdkWindow *window, const GdkRectangle *area, double width=1)
0237 {
0238     return gdkCreateClip(window, (const QtcRect*)area, width);
0239 }
0240 #endif
0241 
0242 }
0243 }
0244 
0245 #endif