1 /************************************************************************ 2 * 3 * Copyright 2013 Jakob Leben (jakob.leben@gmail.com) 4 * 5 * This file is part of SuperCollider Qt GUI. 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * 20 ************************************************************************/ 21 22 #pragma once 23 24 #include "../image.h" 25 #include "../debug.h" 26 27 #include <QPainter> 28 29 namespace QtCollider { 30 31 struct ImagePainter { 32 enum HorizontalMode { 33 AlignLeft, 34 AlignHCenter, 35 AlignRight, 36 TileHorizontally, 37 StretchHorizontally, 38 }; 39 40 enum VerticalMode { AlignTop, AlignVCenter, AlignBottom, TileVertically, StretchVertically }; 41 42 SharedImage image; 43 QRectF sourceRect; 44 HorizontalMode horizontalMode; 45 VerticalMode verticalMode; 46 bool scaleToFit; 47 qreal opacity; 48 ImagePainterImagePainter49 ImagePainter(): horizontalMode(AlignLeft), verticalMode(AlignTop), scaleToFit(false), opacity(1.0) {} 50 isValidImagePainter51 bool isValid() const { return !image.isNull(); } 52 53 void setImage(const SharedImage& image, const QRectF& rect = QRectF(), int tileMode = 1, qreal opacity = 1.0) { 54 this->image = image; 55 this->sourceRect = rect; 56 this->opacity = opacity; 57 setTileMode(tileMode); 58 } 59 clearImagePainter60 void clear() { image.clear(); } 61 paintImagePainter62 void paint(QPainter* painter, const QRectF& targetRect) { 63 if (!image) 64 return; 65 66 if (image->isPainting()) { 67 qcErrorMsg("Can not draw image while being painted."); 68 return; 69 } 70 71 const QPixmap& pixmap = image->pixmap(); 72 73 if (sourceRect.isNull() || targetRect.isNull()) 74 return; 75 76 painter->save(); 77 painter->setOpacity(opacity); 78 painter->setRenderHint(QPainter::SmoothPixmapTransform, image->transformationMode == Qt::SmoothTransformation); 79 80 QRectF rect = sourceRect; 81 qreal ratio = pixmap.devicePixelRatio(); 82 rect.setWidth(rect.width() / ratio); 83 rect.setHeight(rect.height() / ratio); 84 85 if (horizontalMode == StretchHorizontally) { 86 rect.moveLeft(targetRect.left()); 87 rect.setWidth(targetRect.width()); 88 } 89 if (verticalMode == StretchVertically) { 90 rect.moveTop(targetRect.top()); 91 rect.setHeight(targetRect.height()); 92 } 93 if (horizontalMode != StretchHorizontally && verticalMode != StretchVertically && scaleToFit) { 94 float aspect_ratio = rect.width() / rect.height(); 95 rect.setHeight(targetRect.height()); 96 rect.setWidth(rect.height() * aspect_ratio); 97 if (rect.width() > targetRect.width()) { 98 rect.setWidth(targetRect.width()); 99 rect.setHeight(rect.width() / aspect_ratio); 100 } 101 } 102 103 switch (horizontalMode) { 104 case AlignLeft: 105 case TileHorizontally: 106 rect.moveLeft(targetRect.left()); 107 break; 108 case AlignHCenter: 109 rect.moveLeft(targetRect.left() + targetRect.width() / 2 - rect.width() / 2); 110 break; 111 case AlignRight: 112 rect.moveRight(targetRect.right()); 113 break; 114 default: 115 break; 116 }; 117 118 switch (verticalMode) { 119 case AlignTop: 120 case TileVertically: 121 rect.moveTop(targetRect.top()); 122 break; 123 case AlignVCenter: 124 rect.moveTop(targetRect.top() + targetRect.height() / 2 - rect.height() / 2); 125 break; 126 case AlignRight: 127 rect.moveBottom(targetRect.bottom()); 128 break; 129 default: 130 break; 131 }; 132 133 bool tileVertically = verticalMode == TileVertically; 134 bool tileHorizontally = horizontalMode == TileHorizontally; 135 136 qreal y_origin = rect.top(); 137 do { 138 do { 139 painter->drawPixmap(rect, pixmap, sourceRect); 140 141 if (tileVertically) 142 rect.moveTop(rect.top() + rect.height()); 143 else 144 break; 145 } while (rect.top() <= targetRect.bottom()); 146 147 if (tileHorizontally) { 148 rect.moveTop(y_origin); 149 rect.moveLeft(rect.left() + rect.width()); 150 } else 151 break; 152 } while (rect.left() <= targetRect.right()); 153 154 painter->restore(); 155 } 156 setTileModeImagePainter157 void setTileMode(const int mode) { 158 /* 159 modes : 160 1 - fixed to left, fixed to top 161 2 - horizontally tile, fixed to top 162 3 - fixed to right, fixed to top 163 4 - fixed to left, vertically tile 164 5 - horizontally tile, vertically tile 165 6 - fixed to right, vertically tile 166 7 - fixed to left, fixed to bottom 167 8 - horizontally tile, fixed to bottom 168 9 - fixed to right, fixed to bottom 169 10 - fit 170 11 - center, center (scale) 171 12 - center , fixed to top 172 13 - center , fixed to bottom 173 14 - fixed to left, center 174 15 - fixed to right, center 175 16 - center, center (no scale) 176 */ 177 178 int mode_map_index = mode - 1; 179 if (mode_map_index < 0 || mode_map_index >= 16) 180 return; 181 182 static int mode_map[16][2] = { { AlignLeft, AlignTop }, 183 { TileHorizontally, AlignTop }, 184 { AlignRight, AlignTop }, 185 { AlignLeft, TileVertically }, 186 { TileHorizontally, TileVertically }, 187 { AlignRight, TileVertically }, 188 { AlignLeft, AlignBottom }, 189 { TileHorizontally, AlignBottom }, 190 { AlignRight, AlignBottom }, 191 { StretchHorizontally, StretchVertically }, 192 { AlignHCenter, AlignVCenter }, 193 { AlignHCenter, AlignTop }, 194 { AlignHCenter, AlignBottom }, 195 { AlignLeft, AlignVCenter }, 196 { AlignRight, AlignVCenter }, 197 { AlignHCenter, AlignVCenter } }; 198 199 horizontalMode = (HorizontalMode)mode_map[mode_map_index][0]; 200 verticalMode = (VerticalMode)mode_map[mode_map_index][1]; 201 scaleToFit = (mode == 11); 202 } 203 }; 204 205 } // namespace QtCollider 206