1 /* 2 SPDX-FileCopyrightText: 2008 Aaron Seigo <aseigo@kde.org> 3 SPDX-FileCopyrightText: 2008 Marco Martin <notmart@gmail.com> 4 5 SPDX-License-Identifier: LGPL-2.0-or-later 6 */ 7 8 #ifndef PLASMA_FRAMESVG_H 9 #define PLASMA_FRAMESVG_H 10 11 #include <QObject> 12 #include <QPixmap> 13 14 #include <plasma/plasma_export.h> 15 16 #include <plasma/plasma.h> 17 #include <plasma/svg.h> 18 19 class QPainter; 20 class QPoint; 21 class QPointF; 22 class QRect; 23 class QRectF; 24 class QSize; 25 class QSizeF; 26 class QMatrix; 27 28 namespace Plasma 29 { 30 class FrameSvgPrivate; 31 32 /** 33 * @class FrameSvg plasma/framesvg.h <Plasma/FrameSvg> 34 * 35 * @short Provides an SVG with borders. 36 * 37 * When using SVG images for a background of an object that may change 38 * its aspect ratio, such as a dialog, simply scaling a single image 39 * may not be enough. 40 * 41 * FrameSvg allows SVGs to provide several elements for borders as well 42 * as a central element, each of which are scaled individually. These 43 * elements should be named 44 * 45 * - @c center - the central element, which will be scaled in both directions 46 * - @c top - the top border; the height is fixed, but it will be scaled 47 * horizontally to the same width as @c center 48 * - @c bottom - the bottom border; scaled in the same way as @c top 49 * - @c left - the left border; the width is fixed, but it will be scaled 50 * vertically to the same height as @c center 51 * - @c right - the right border; scaled in the same way as @c left 52 * - @c topleft - fixed size; must be the same height as @c top and the same 53 * width as @c left 54 * - @c bottomleft, @c topright, @c bottomright - similar to @c topleft 55 * 56 * @c center must exist, but all the others are optional. @c topleft and 57 * @c topright will be ignored if @c top does not exist, and similarly for 58 * @c bottomleft and @c bottomright. 59 * 60 * @see Plasma::Svg 61 **/ 62 class PLASMA_EXPORT FrameSvg : public Svg 63 { 64 Q_OBJECT 65 66 Q_PROPERTY(EnabledBorders enabledBorders READ enabledBorders WRITE setEnabledBorders) 67 68 public: 69 /** 70 * These flags represents what borders should be drawn 71 */ 72 enum EnabledBorder { 73 NoBorder = 0, 74 TopBorder = 1, 75 BottomBorder = 2, 76 LeftBorder = 4, 77 RightBorder = 8, 78 AllBorders = TopBorder | BottomBorder | LeftBorder | RightBorder, 79 }; 80 Q_DECLARE_FLAGS(EnabledBorders, EnabledBorder) 81 Q_FLAG(EnabledBorders) 82 83 /** 84 * Constructs a new FrameSvg that paints the proper named subelements 85 * as borders. It may also be used as a regular Plasma::Svg object 86 * for direct access to elements in the Svg. 87 * 88 * @param parent options QObject to parent this to 89 * 90 * @related Plasma::Theme 91 */ 92 explicit FrameSvg(QObject *parent = nullptr); 93 ~FrameSvg() override; 94 95 /** 96 * Loads a new Svg 97 * @param imagePath the new file 98 */ 99 Q_INVOKABLE void setImagePath(const QString &path) override; 100 101 /** 102 * Sets what borders should be painted 103 * @param flags borders we want to paint 104 */ 105 void setEnabledBorders(const EnabledBorders borders); 106 107 /** 108 * Convenience method to get the enabled borders 109 * @return what borders are painted 110 */ 111 EnabledBorders enabledBorders() const; 112 113 /** 114 * Resize the frame maintaining the same border size 115 * @param size the new size of the frame 116 */ 117 Q_INVOKABLE void resizeFrame(const QSizeF &size); 118 119 /** 120 * @returns the size of the frame 121 */ 122 Q_INVOKABLE QSizeF frameSize() const; 123 124 /** 125 * Returns the margin size given the margin edge we want 126 * If the given margin is disabled, it will return 0. 127 * If you don't care about the margin being on or off, use fixedMarginSize() 128 * @param edge the margin edge we want, top, bottom, left or right 129 * @return the margin size 130 */ 131 Q_INVOKABLE qreal marginSize(const Plasma::Types::MarginEdge edge) const; 132 133 /** 134 * Convenience method that extracts the size of the four margins 135 * in the four output parameters 136 * The disabled margins will be 0. 137 * If you don't care about the margins being on or off, use getFixedMargins() 138 * @param left left margin size 139 * @param top top margin size 140 * @param right right margin size 141 * @param bottom bottom margin size 142 */ 143 Q_INVOKABLE void getMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const; 144 145 /** 146 * Returns the margin size given the margin edge we want. 147 * Compared to marginSize(), this doesn't depend whether the margin is enabled or not 148 * @param edge the margin edge we want, top, bottom, left or right 149 * @return the margin size 150 */ 151 Q_INVOKABLE qreal fixedMarginSize(const Plasma::Types::MarginEdge edge) const; 152 153 /** 154 * Convenience method that extracts the size of the four margins 155 * in the four output parameters 156 * Compared to getMargins(), this doesn't depend whether the margins are enabled or not 157 * @param left left margin size 158 * @param top top margin size 159 * @param right right margin size 160 * @param bottom bottom margin size 161 */ 162 Q_INVOKABLE void getFixedMargins(qreal &left, qreal &top, qreal &right, qreal &bottom) const; 163 164 /** 165 * Returns the insets margin size given the margin edge we want. 166 * @param edge the margin edge we want, top, bottom, left or right 167 * @return the margin size 168 * @since 5.77 169 */ 170 Q_INVOKABLE qreal insetSize(const Plasma::Types::MarginEdge edge) const; 171 172 /** 173 * Convenience method that extracts the size of the four inset margins 174 * in the four output parameters 175 * @param left left margin size 176 * @param top top margin size 177 * @param right right margin size 178 * @param bottom bottom margin size 179 * @since 5.77 180 */ 181 Q_INVOKABLE void getInset(qreal &left, qreal &top, qreal &right, qreal &bottom) const; 182 183 /** 184 * @return the rectangle of the center element, taking the margins into account. 185 */ 186 Q_INVOKABLE QRectF contentsRect() const; 187 188 /** 189 * Sets the prefix (@see setElementPrefix) to 'north', 'south', 'west' and 'east' 190 * when the location is TopEdge, BottomEdge, LeftEdge and RightEdge, 191 * respectively. Clears the prefix in other cases. 192 * 193 * The prefix must exist in the SVG document, which means that this can only be 194 * called successfully after setImagePath is called. 195 * @param location location in the UI this frame will be drawn 196 */ 197 Q_INVOKABLE void setElementPrefix(Plasma::Types::Location location); 198 199 /** 200 * Sets the prefix for the SVG elements to be used for painting. For example, 201 * if prefix is 'active', then instead of using the 'top' element of the SVG 202 * file to paint the top border, 'active-top' element will be used. The same 203 * goes for other SVG elements. 204 * 205 * If the elements with prefixes are not present, the default ones are used. 206 * (for the sake of speed, the test is present only for the 'center' element) 207 * 208 * Setting the prefix manually resets the location to Floating. 209 * 210 * The prefix must exist in the SVG document, which means that this can only be 211 * called successfully after setImagePath is called. 212 * 213 * @param prefix prefix for the SVG elements that make up the frame 214 */ 215 Q_INVOKABLE void setElementPrefix(const QString &prefix); 216 217 /** 218 * @return true if the svg has the necessary elements with the given prefix 219 * to draw a frame 220 * @param prefix the given prefix we want to check if drawable (can have trailing '-' since 5.59) 221 */ 222 Q_INVOKABLE bool hasElementPrefix(const QString &prefix) const; 223 224 /** 225 * This is an overloaded method provided for convenience equivalent to 226 * hasElementPrefix("north"), hasElementPrefix("south") 227 * hasElementPrefix("west") and hasElementPrefix("east") 228 * @return true if the svg has the necessary elements with the given prefix 229 * to draw a frame. 230 * @param location the given prefix we want to check if drawable 231 */ 232 Q_INVOKABLE bool hasElementPrefix(Plasma::Types::Location location) const; 233 234 /** 235 * Returns the prefix for SVG elements of the FrameSvg (including a '-' at the end if not empty) 236 * @return the prefix 237 * @sa actualPrefix() 238 */ 239 Q_INVOKABLE QString prefix(); 240 241 /** 242 * Returns a mask that tightly contains the fully opaque areas of the svg 243 * @return a region of opaque areas 244 */ 245 Q_INVOKABLE QRegion mask() const; 246 247 /** 248 * @return a pixmap whose alpha channel is the opacity of the frame. It may be the frame itself or a special frame with the mask- prefix 249 */ 250 QPixmap alphaMask() const; 251 252 /** 253 * Sets whether saving all the rendered prefixes in a cache or not 254 * @param cache if use the cache or not 255 */ 256 Q_INVOKABLE void setCacheAllRenderedFrames(bool cache); 257 258 /** 259 * @return if all the different prefixes should be kept in a cache when rendered 260 */ 261 Q_INVOKABLE bool cacheAllRenderedFrames() const; 262 263 /** 264 * Deletes the internal cache freeing memory: use this if you want to switch the rendered 265 * element and you don't plan to switch back to the previous one for a long time and you 266 * used setUsingRenderingCache(true) 267 */ 268 Q_INVOKABLE void clearCache(); 269 270 /** 271 * Returns a pixmap of the SVG represented by this object. 272 * 273 * @param elelementId the ID string of the element to render, or an empty 274 * string for the whole SVG (the default) 275 * @return a QPixmap of the rendered SVG 276 */ 277 Q_INVOKABLE QPixmap framePixmap(); 278 279 /** 280 * Paints the loaded SVG with the elements that represents the border 281 * @param painter the QPainter to use 282 * @param target the target rectangle on the paint device 283 * @param source the portion rectangle of the source image 284 */ 285 Q_INVOKABLE void paintFrame(QPainter *painter, const QRectF &target, const QRectF &source = QRectF()); 286 287 /** 288 * Paints the loaded SVG with the elements that represents the border 289 * This is an overloaded member provided for convenience 290 * @param painter the QPainter to use 291 * @param pos where to paint the svg 292 */ 293 Q_INVOKABLE void paintFrame(QPainter *painter, const QPointF &pos = QPointF(0, 0)); 294 295 /** 296 * @returns the prefix that is actually used (including a '-' at the end if not empty) 297 * @sa prefix() 298 */ 299 QString actualPrefix() const; 300 301 /** 302 * @returns true if we are in a transaction of many changes at once 303 * and we don't want to rebuild the generated graphics for each change yet 304 * @since 5.31 305 */ 306 bool isRepaintBlocked() const; 307 308 /** 309 * If we will do several changes at once in the frame properties, 310 * such as prefix, enabled borders and size, in order to not regenerate 311 * the graphics for each change, set this property to true, and set 312 * it to false again after applying all the changes needed. 313 * Note that any change will not be visible in the painted frame while this property is set to true. 314 * @since 5.31 315 */ 316 void setRepaintBlocked(bool blocked); 317 318 private: 319 FrameSvgPrivate *const d; 320 friend class FrameData; 321 322 // Q_PRIVATE_SLOT(d, void updateSizes()) 323 }; 324 325 Q_DECLARE_OPERATORS_FOR_FLAGS(FrameSvg::EnabledBorders) 326 327 } // Plasma namespace 328 329 #endif // multiple inclusion guard 330