File indexing completed on 2024-05-12 09:52:48

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 #include "draw.h"
0024 #include "utils_p.h"
0025 #include <pango/pangocairo.h>
0026 
0027 namespace QtCurve {
0028 namespace Cairo {
0029 
0030 QTC_EXPORT void
0031 hLine(cairo_t *cr, int x, int y, int w, const GdkColor *col, double a)
0032 {
0033     Saver saver(cr);
0034     cairo_new_path(cr);
0035     setColor(cr, col, a);
0036     cairo_move_to(cr, x, y + 0.5);
0037     cairo_line_to(cr, x + w, y + 0.5);
0038     cairo_stroke(cr);
0039 }
0040 
0041 QTC_EXPORT void
0042 vLine(cairo_t *cr, int x, int y, int h, const GdkColor *col, double a)
0043 {
0044     Saver saver(cr);
0045     cairo_new_path(cr);
0046     setColor(cr, col, a);
0047     cairo_move_to(cr, x + 0.5, y);
0048     cairo_line_to(cr, x + 0.5, y + h);
0049     cairo_stroke(cr);
0050 }
0051 
0052 QTC_EXPORT void
0053 polygon(cairo_t *cr, const GdkColor *col, const QtcRect *area,
0054         const GdkPoint *points, int npoints, bool fill)
0055 {
0056     Saver saver(cr);
0057     cairo_set_line_width(cr, 1);
0058     clipRect(cr, area);
0059     setColor(cr, col);
0060     cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
0061     pathPoints(cr, points, npoints);
0062     cairo_close_path(cr);
0063     cairo_stroke_preserve(cr);
0064     if (fill) {
0065         cairo_fill(cr);
0066     }
0067 }
0068 
0069 QTC_EXPORT void
0070 rect(cairo_t *cr, const QtcRect *area, int x, int y, int width, int height,
0071      const GdkColor *col, double alpha)
0072 {
0073     Saver saver(cr);
0074     clipRect(cr, area);
0075     cairo_rectangle(cr, x, y, width, height);
0076     setColor(cr, col, alpha);
0077     cairo_fill(cr);
0078 }
0079 
0080 QTC_EXPORT void
0081 fadedLine(cairo_t *cr, int x, int y, int width, int height,
0082           const QtcRect *area, const QtcRect *gap, bool fadeStart,
0083           bool fadeEnd, double fadeSize, bool horiz,
0084           const GdkColor *col, double alpha)
0085 {
0086     double rx = x + 0.5;
0087     double ry = y + 0.5;
0088     cairo_pattern_t *pt =
0089         cairo_pattern_create_linear(rx, ry, horiz ? rx + width - 1 : rx + 1,
0090                                     horiz ? ry + 1 : ry + height - 1);
0091 
0092     Saver saver(cr);
0093     if (gap) {
0094         QtcRect r = {x, y, width, height};
0095         cairo_region_t *region =
0096             cairo_region_create_rectangle(area ? area : &r);
0097         cairo_region_xor_rectangle(region, gap);
0098         clipRegion(cr, region);
0099         cairo_region_destroy(region);
0100     } else {
0101         clipRect(cr, area);
0102     }
0103     patternAddColorStop(pt, 0, col, fadeStart ? 0.0 : alpha);
0104     patternAddColorStop(pt, fadeSize, col, alpha);
0105     patternAddColorStop(pt, 1 - fadeSize, col, alpha);
0106     patternAddColorStop(pt, 1, col, fadeEnd ? 0.0 : alpha);
0107     cairo_set_source(cr, pt);
0108     if (horiz) {
0109         cairo_move_to(cr, x, ry);
0110         cairo_line_to(cr, x + width - 1, ry);
0111     } else {
0112         cairo_move_to(cr, rx, y);
0113         cairo_line_to(cr, rx, y + height - 1);
0114     }
0115     cairo_stroke(cr);
0116     cairo_pattern_destroy(pt);
0117 }
0118 
0119 QTC_EXPORT void
0120 stripes(cairo_t *cr, int x, int y, int w, int h,
0121         bool horizontal, int stripeWidth)
0122 {
0123     int endx = horizontal ? stripeWidth : 0;
0124     int endy = horizontal ? 0 : stripeWidth;
0125     cairo_pattern_t *pat =
0126         cairo_pattern_create_linear(x, y, x + endx, y + endy);
0127     cairo_pattern_add_color_stop_rgba(pat, 0.0, 1.0, 1.0, 1.0, 0.0);
0128     cairo_pattern_add_color_stop_rgba(pat, 1, 1.0, 1.0, 1.0, 0.15);
0129     cairo_pattern_set_extend(pat, CAIRO_EXTEND_REFLECT);
0130 
0131     Saver saver(cr);
0132     cairo_set_source(cr, pat);
0133     cairo_rectangle(cr, x, y, w, h);
0134     cairo_fill(cr);
0135 
0136     cairo_pattern_destroy(pat);
0137 }
0138 
0139 QTC_EXPORT void
0140 dot(cairo_t *cr, int x, int y, int w, int h, const GdkColor *col)
0141 {
0142     double dx = x + (w - 5) / 2;
0143     double dy = y + (h - 5) / 2;
0144     cairo_pattern_t *p1 = cairo_pattern_create_linear(dx, dy, dx + 4, dy + 4);
0145     cairo_pattern_t *p2 = cairo_pattern_create_linear(dx + 2, dy + 2,
0146                                                       dx + 4, dx + 4);
0147 
0148     patternAddColorStop(p1, 0, col, 1);
0149     patternAddColorStop(p1, 1, col, 0.4);
0150     cairo_pattern_add_color_stop_rgba(p2, 1, 1, 1, 1, 0.9);
0151     cairo_pattern_add_color_stop_rgba(p2, 0, 1, 1, 1, 0.7);
0152 
0153     Saver saver(cr);
0154     cairo_new_path(cr);
0155     cairo_arc(cr, dx + 2.5, dy + 2.5, 2.5, 0, 2 * M_PI);
0156     cairo_clip(cr);
0157     cairo_set_source(cr, p1);
0158     cairo_rectangle(cr, dx, dy, 5, 5);
0159     cairo_fill(cr);
0160 
0161     cairo_new_path(cr);
0162     cairo_arc(cr, dx + 3, dy + 3, 2, 0, 2 * M_PI);
0163     cairo_clip(cr);
0164     cairo_set_source(cr, p2);
0165     cairo_rectangle(cr, dx + 1, dy + 1, 4, 4);
0166     cairo_fill(cr);
0167 
0168     cairo_pattern_destroy(p1);
0169     cairo_pattern_destroy(p2);
0170 }
0171 
0172 QTC_EXPORT void
0173 dots(cairo_t *cr, int rx, int ry, int rwidth, int rheight, bool horiz,
0174      int nLines, int offset, const QtcRect *area, int startOffset,
0175      const GdkColor *col1, const GdkColor *col2)
0176 {
0177     int space = nLines * 2 + nLines - 1;
0178     int x = horiz ? rx : rx + (rwidth - space) / 2;
0179     int y = horiz ? ry + (rheight - space) / 2 : ry;
0180     int numDots = ((horiz ? rwidth : rheight) - 2 * offset) / 3 + 1;
0181 
0182     Saver saver(cr);
0183     clipRect(cr, area);
0184     if (horiz) {
0185         if (startOffset && y + startOffset > 0) {
0186             y += startOffset;
0187         }
0188         cairo_new_path(cr);
0189         setColor(cr, col1);
0190         for (int i = 0;i < space;i += 3) {
0191             for (int j = 0;j < numDots;j++) {
0192                 cairo_rectangle(cr, x + offset + 3 * j, y + i, 1, 1);
0193             }
0194         }
0195         cairo_fill(cr);
0196 
0197         cairo_new_path(cr);
0198         setColor(cr, col2);
0199         for (int i = 1;i < space;i += 3) {
0200             for (int j = 0;j < numDots;j++) {
0201                 cairo_rectangle(cr, x + offset + 1 + 3 * j, y + i, 1, 1);
0202             }
0203         }
0204         cairo_fill(cr);
0205     } else {
0206         if (startOffset && x + startOffset > 0) {
0207             x += startOffset;
0208         }
0209         cairo_new_path(cr);
0210         setColor(cr, col1);
0211         for (int i = 0;i < space;i += 3) {
0212             for (int j = 0;j < numDots;j++) {
0213                 cairo_rectangle(cr, x + i, y + offset + 3 * j, 1, 1);
0214             }
0215         }
0216         cairo_fill(cr);
0217 
0218         cairo_new_path(cr);
0219         setColor(cr, col2);
0220         for (int i = 1;i < space;i += 3) {
0221             for(int j = 0;j < numDots;j++) {
0222                 cairo_rectangle(cr, x + i, y + offset + 1 + 3 * j, 1, 1);
0223             }
0224         }
0225         cairo_fill(cr);
0226     }
0227 }
0228 
0229 static void
0230 ge_transform_for_layout(cairo_t *cr, PangoLayout *layout, int x, int y)
0231 {
0232     const PangoMatrix *matrix =
0233         pango_context_get_matrix(pango_layout_get_context(layout));
0234     if (matrix) {
0235         cairo_matrix_t cairo_matrix;
0236         PangoRectangle _rect;
0237 
0238         cairo_matrix_init(&cairo_matrix, matrix->xx, matrix->yx,
0239                           matrix->xy, matrix->yy, matrix->x0, matrix->y0);
0240         pango_layout_get_extents(layout, nullptr, &_rect);
0241         pango_matrix_transform_rectangle(matrix, &_rect);
0242         pango_extents_to_pixels(&_rect, nullptr);
0243 
0244         cairo_matrix.x0 += x - _rect.x;
0245         cairo_matrix.y0 += y - _rect.y;
0246 
0247         cairo_set_matrix(cr, &cairo_matrix);
0248     } else {
0249         cairo_translate(cr, x, y);
0250     }
0251 }
0252 
0253 QTC_EXPORT void
0254 layout(cairo_t *cr, const QtcRect *area, int x, int y, PangoLayout *_layout,
0255        const GdkColor *col)
0256 {
0257     Saver saver(cr);
0258     clipRect(cr, area);
0259     cairo_set_line_width(cr, 1);
0260     setColor(cr, col);
0261     ge_transform_for_layout(cr, _layout, x, y);
0262     pango_cairo_show_layout(cr, _layout);
0263 }
0264 
0265 QTC_EXPORT void
0266 arrow(cairo_t *cr, const GdkColor *col, const QtcRect *area,
0267       ArrowType arrow_type, int x, int y, bool small, bool fill, bool varrow)
0268 {
0269     if (small) {
0270         switch (arrow_type) {
0271         case ArrowType::Up: {
0272             const GdkPoint a[] = {{x + 2, y}, {x, y - 2}, {x - 2, y},
0273                                   {x - 2, y + 1}, {x, y - 1}, {x + 2, y + 1}};
0274             polygon(cr, col, area, a, varrow ? 6 : 3, fill);
0275             break;
0276         }
0277         case ArrowType::Down: {
0278             const GdkPoint a[] = {{x + 2, y}, {x, y + 2}, {x - 2, y},
0279                                   {x - 2, y - 1}, {x, y + 1}, {x + 2, y - 1}};
0280             polygon(cr, col, area, a, varrow ? 6 : 3, fill);
0281             break;
0282         }
0283         case ArrowType::Right: {
0284             const GdkPoint a[] = {{x, y - 2}, {x + 2, y}, {x, y + 2},
0285                                   {x - 1, y + 2}, {x + 1, y}, {x - 1, y - 2}};
0286             polygon(cr, col, area, a, varrow ? 6 : 3, fill);
0287             break;
0288         }
0289         case ArrowType::Left: {
0290             const GdkPoint a[] = {{x, y - 2}, {x - 2, y}, {x, y + 2},
0291                                   {x + 1, y + 2}, {x - 1, y}, {x + 1, y - 2}};
0292             polygon(cr, col, area, a, varrow ? 6 : 3, fill);
0293             break;
0294         }
0295         default:
0296             break;
0297         }
0298     } else {
0299         /* Large arrows... */
0300         switch (arrow_type) {
0301         case ArrowType::Up: {
0302             const GdkPoint a[] = {{x + 3, y + 1}, {x, y - 2}, {x - 3, y + 1},
0303                                   {x - 3, y + 2}, {x - 2, y + 2}, {x, y},
0304                                   {x + 2, y + 2}, {x + 3, y + 2}};
0305             polygon(cr, col, area, a, varrow ? 8 : 3, fill);
0306             break;
0307         }
0308         case ArrowType::Down: {
0309             const GdkPoint a[] = {{x + 3, y - 1}, {x, y + 2}, {x - 3, y - 1},
0310                                   {x - 3, y - 2}, {x - 2, y - 2}, {x, y},
0311                                   {x + 2, y - 2}, {x + 3,y - 2}};
0312             polygon(cr, col, area, a, varrow ? 8 : 3, fill);
0313             break;
0314         }
0315         case ArrowType::Right: {
0316             const GdkPoint a[] = {{x - 1, y + 3}, {x + 2, y}, {x - 1, y - 3},
0317                                   {x - 2, y - 3}, {x - 2, y - 2}, {x, y},
0318                                   {x - 2, y + 2}, {x - 2, y + 3}};
0319             polygon(cr, col, area, a, varrow ? 8 : 3, fill);
0320             break;
0321         }
0322         case ArrowType::Left: {
0323             const GdkPoint a[] = {{x + 1, y - 3}, {x - 2, y}, {x + 1, y + 3},
0324                                   {x + 2, y + 3}, {x + 2, y + 2}, {x, y},
0325                                   {x + 2, y - 2}, {x + 2, y - 3}};
0326             polygon(cr, col, area, a, varrow ? 8 : 3, fill);
0327             break;
0328         }
0329         default:
0330             break;
0331         }
0332     }
0333 }
0334 
0335 }
0336 }