File indexing completed on 2024-05-12 17:06:32

0001 /*
0002     SPDX-FileCopyrightText: 2009-2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0003     SPDX-FileCopyrightText: 2008 Long Huynh Huu <long.upcase@googlemail.com>
0004     SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-only
0007 */
0008 
0009 #include "oxygentileset.h"
0010 
0011 #include <QPainter>
0012 
0013 namespace Oxygen
0014 {
0015 
0016 //___________________________________________________________
0017 inline bool bits(TileSet::Tiles flags, TileSet::Tiles testFlags)
0018 {
0019     return (flags & testFlags) == testFlags;
0020 }
0021 
0022 //______________________________________________________________________________________
0023 inline qreal devicePixelRatio(const QPixmap &pixmap)
0024 {
0025     return pixmap.devicePixelRatio();
0026 }
0027 
0028 //______________________________________________________________________________________
0029 inline void setDevicePixelRatio(QPixmap &pixmap, qreal value)
0030 {
0031     return pixmap.setDevicePixelRatio(value);
0032 }
0033 
0034 //______________________________________________________________
0035 int TileSet::_sideExtent = 32;
0036 
0037 //______________________________________________________________
0038 void TileSet::initPixmap(PixmapList &pixmaps, const QPixmap &source, int width, int height, const QRect &rect)
0039 {
0040     QSize size(width, height);
0041     if (!(size.isValid() && rect.isValid())) {
0042         pixmaps.append(QPixmap());
0043 
0044     } else if (size != rect.size()) {
0045         const qreal dpiRatio(devicePixelRatio(source));
0046         const QRect scaledRect(rect.topLeft() * dpiRatio, rect.size() * dpiRatio);
0047         const QSize scaledSize(size * dpiRatio);
0048         const QPixmap tile(source.copy(scaledRect));
0049         QPixmap pixmap(scaledSize);
0050 
0051         pixmap.fill(Qt::transparent);
0052         QPainter painter(&pixmap);
0053         painter.drawTiledPixmap(0, 0, scaledSize.width(), scaledSize.height(), tile);
0054         setDevicePixelRatio(pixmap, dpiRatio);
0055         pixmaps.append(pixmap);
0056 
0057     } else {
0058         const qreal dpiRatio(devicePixelRatio(source));
0059         const QRect scaledRect(rect.topLeft() * dpiRatio, rect.size() * dpiRatio);
0060         QPixmap pixmap(source.copy(scaledRect));
0061         setDevicePixelRatio(pixmap, dpiRatio);
0062         pixmaps.append(pixmap);
0063     }
0064 }
0065 
0066 //______________________________________________________________
0067 TileSet::TileSet(void)
0068     : _w1(0)
0069     , _h1(0)
0070     , _w3(0)
0071     , _h3(0)
0072 {
0073     _pixmaps.reserve(9);
0074 }
0075 
0076 //______________________________________________________________
0077 TileSet::TileSet(const QPixmap &source, int w1, int h1, int w2, int h2)
0078     : _w1(w1)
0079     , _h1(h1)
0080     , _w3(0)
0081     , _h3(0)
0082 {
0083     _pixmaps.reserve(9);
0084     if (source.isNull())
0085         return;
0086 
0087     _w3 = source.width() / devicePixelRatio(source) - (w1 + w2);
0088     _h3 = source.height() / devicePixelRatio(source) - (h1 + h2);
0089     int w = w2;
0090     int h = h2;
0091 
0092     // initialise pixmap array
0093     initPixmap(_pixmaps, source, _w1, _h1, QRect(0, 0, _w1, _h1));
0094     initPixmap(_pixmaps, source, w, _h1, QRect(_w1, 0, w2, _h1));
0095     initPixmap(_pixmaps, source, _w3, _h1, QRect(_w1 + w2, 0, _w3, _h1));
0096     initPixmap(_pixmaps, source, _w1, h, QRect(0, _h1, _w1, h2));
0097     initPixmap(_pixmaps, source, w, h, QRect(_w1, _h1, w2, h2));
0098     initPixmap(_pixmaps, source, _w3, h, QRect(_w1 + w2, _h1, _w3, h2));
0099     initPixmap(_pixmaps, source, _w1, _h3, QRect(0, _h1 + h2, _w1, _h3));
0100     initPixmap(_pixmaps, source, w, _h3, QRect(_w1, _h1 + h2, w2, _h3));
0101     initPixmap(_pixmaps, source, _w3, _h3, QRect(_w1 + w2, _h1 + h2, _w3, _h3));
0102 }
0103 
0104 //______________________________________________________________
0105 TileSet::TileSet(const QPixmap &source, int w1, int h1, int w3, int h3, int x1, int y1, int w2, int h2)
0106     : _w1(w1)
0107     , _h1(h1)
0108     , _w3(w3)
0109     , _h3(h3)
0110 {
0111     _pixmaps.reserve(9);
0112     if (source.isNull())
0113         return;
0114 
0115     int x2 = source.width() / devicePixelRatio(source) - _w3;
0116     int y2 = source.height() / devicePixelRatio(source) - _h3;
0117     int w = w2;
0118     int h = h2;
0119 
0120     // initialise pixmap array
0121     initPixmap(_pixmaps, source, _w1, _h1, QRect(0, 0, _w1, _h1));
0122     initPixmap(_pixmaps, source, w, _h1, QRect(x1, 0, w2, _h1));
0123     initPixmap(_pixmaps, source, _w3, _h1, QRect(x2, 0, _w3, _h1));
0124     initPixmap(_pixmaps, source, _w1, h, QRect(0, y1, _w1, h2));
0125     initPixmap(_pixmaps, source, w, h, QRect(x1, y1, w2, h2));
0126     initPixmap(_pixmaps, source, _w3, h, QRect(x2, y1, _w3, h2));
0127     initPixmap(_pixmaps, source, _w1, _h3, QRect(0, y2, _w1, _h3));
0128     initPixmap(_pixmaps, source, w, _h3, QRect(x1, y2, w2, _h3));
0129     initPixmap(_pixmaps, source, _w3, _h3, QRect(x2, y2, _w3, _h3));
0130 }
0131 
0132 //___________________________________________________________
0133 QRect TileSet::adjust(const QRect &constRect, Tiles tiles) const
0134 {
0135     // adjust rect to deal with missing edges
0136     QRect rect(constRect);
0137     if (!(tiles & Left))
0138         rect.adjust(-_w1, 0, 0, 0);
0139     if (!(tiles & Right))
0140         rect.adjust(0, 0, _w3, 0);
0141     if (!(tiles & Top))
0142         rect.adjust(0, -_h1, 0, 0);
0143     if (!(tiles & Bottom))
0144         rect.adjust(0, 0, 0, _h3);
0145 
0146     return rect;
0147 }
0148 
0149 //___________________________________________________________
0150 void TileSet::render(const QRect &constRect, QPainter *painter, Tiles tiles) const
0151 {
0152     const bool oldHint(painter->testRenderHint(QPainter::SmoothPixmapTransform));
0153     painter->setRenderHint(QPainter::SmoothPixmapTransform, true);
0154 
0155     // check initialization
0156     if (_pixmaps.size() < 9)
0157         return;
0158 
0159     // copy source rect
0160     QRect rect(constRect);
0161 
0162     // get rect dimensions
0163     int x0, y0, w, h;
0164     rect.getRect(&x0, &y0, &w, &h);
0165 
0166     // calculate pixmaps widths
0167     int wLeft(0);
0168     int wRight(0);
0169     if (_w1 + _w3 > 0) {
0170         qreal wRatio(qreal(_w1) / qreal(_w1 + _w3));
0171         wLeft = (tiles & Right) ? qMin(_w1, int(w * wRatio)) : _w1;
0172         wRight = (tiles & Left) ? qMin(_w3, int(w * (1.0 - wRatio))) : _w3;
0173     }
0174 
0175     // calculate pixmap heights
0176     int hTop(0);
0177     int hBottom(0);
0178     if (_h1 + _h3 > 0) {
0179         qreal hRatio(qreal(_h1) / qreal(_h1 + _h3));
0180         hTop = (tiles & Bottom) ? qMin(_h1, int(h * hRatio)) : _h1;
0181         hBottom = (tiles & Top) ? qMin(_h3, int(h * (1.0 - hRatio))) : _h3;
0182     }
0183 
0184     // calculate corner locations
0185     w -= wLeft + wRight;
0186     h -= hTop + hBottom;
0187     const int x1 = x0 + wLeft;
0188     const int x2 = x1 + w;
0189     const int y1 = y0 + hTop;
0190     const int y2 = y1 + h;
0191 
0192     const int w2 = _pixmaps.at(7).width() / devicePixelRatio(_pixmaps.at(7));
0193     const int h2 = _pixmaps.at(5).height() / devicePixelRatio(_pixmaps.at(5));
0194 
0195     // corner
0196     if (bits(tiles, Top | Left))
0197         painter->drawPixmap(x0, y0, _pixmaps.at(0), 0, 0, wLeft * devicePixelRatio(_pixmaps.at(0)), hTop * devicePixelRatio(_pixmaps.at(0)));
0198     if (bits(tiles, Top | Right))
0199         painter->drawPixmap(x2,
0200                             y0,
0201                             _pixmaps.at(2),
0202                             (_w3 - wRight) * devicePixelRatio(_pixmaps.at(2)),
0203                             0,
0204                             wRight * devicePixelRatio(_pixmaps.at(2)),
0205                             hTop * devicePixelRatio(_pixmaps.at(2)));
0206     if (bits(tiles, Bottom | Left))
0207         painter->drawPixmap(x0,
0208                             y2,
0209                             _pixmaps.at(6),
0210                             0,
0211                             (_h3 - hBottom) * devicePixelRatio(_pixmaps.at(6)),
0212                             wLeft * devicePixelRatio(_pixmaps.at(6)),
0213                             hBottom * devicePixelRatio(_pixmaps.at(6)));
0214     if (bits(tiles, Bottom | Right))
0215         painter->drawPixmap(x2,
0216                             y2,
0217                             _pixmaps.at(8),
0218                             (_w3 - wRight) * devicePixelRatio(_pixmaps.at(8)),
0219                             (_h3 - hBottom) * devicePixelRatio(_pixmaps.at(8)),
0220                             wRight * devicePixelRatio(_pixmaps.at(8)),
0221                             hBottom * devicePixelRatio(_pixmaps.at(8)));
0222 
0223     // top and bottom
0224     if (w > 0) {
0225         if (tiles & Top)
0226             painter->drawPixmap(x1, y0, w, hTop, _pixmaps.at(1), 0, 0, w2 * devicePixelRatio(_pixmaps.at(1)), hTop * devicePixelRatio(_pixmaps.at(1)));
0227         if (tiles & Bottom)
0228             painter->drawPixmap(x1,
0229                                 y2,
0230                                 w,
0231                                 hBottom,
0232                                 _pixmaps.at(7),
0233                                 0,
0234                                 (_h3 - hBottom) * devicePixelRatio(_pixmaps.at(7)),
0235                                 w2 * devicePixelRatio(_pixmaps.at(7)),
0236                                 hBottom * devicePixelRatio(_pixmaps.at(7)));
0237     }
0238 
0239     // left and right
0240     if (h > 0) {
0241         if (tiles & Left)
0242             painter->drawPixmap(x0, y1, wLeft, h, _pixmaps.at(3), 0, 0, wLeft * devicePixelRatio(_pixmaps.at(3)), h2 * devicePixelRatio(_pixmaps.at(3)));
0243         if (tiles & Right)
0244             painter->drawPixmap(x2,
0245                                 y1,
0246                                 wRight,
0247                                 h,
0248                                 _pixmaps.at(5),
0249                                 (_w3 - wRight) * devicePixelRatio(_pixmaps.at(5)),
0250                                 0,
0251                                 wRight * devicePixelRatio(_pixmaps.at(5)),
0252                                 h2 * devicePixelRatio(_pixmaps.at(5)));
0253     }
0254 
0255     // center
0256     if ((tiles & Center) && h > 0 && w > 0)
0257         painter->drawPixmap(x1, y1, w, h, _pixmaps.at(4));
0258 
0259     // restore
0260     painter->setRenderHint(QPainter::SmoothPixmapTransform, oldHint);
0261 }
0262 }