#include "overlay.h" #include "scripting.h" #include "log.h" void OverlayText::render(QPainter *painter) { QFont font = painter->font(); font.setPixelSize(this->fontSize); painter->setFont(font); painter->setPen(this->color); painter->drawStaticText(this->x, this->y, this->text); } void OverlayPath::render(QPainter *painter) { painter->fillPath(this->path, this->fillColor); painter->setPen(this->borderColor); painter->drawPath(this->path); } void OverlayImage::render(QPainter *painter) { painter->drawImage(this->x, this->y, this->image); } void Overlay::renderItems(QPainter *painter) { if (this->hidden) return; painter->save(); QTransform transform = painter->transform(); transform.translate(this->x, this->y); transform.rotate(this->angle); transform.scale(this->hScale, this->vScale); painter->setTransform(transform); if (this->clippingRect) { painter->setClipping(true); painter->setClipRect(*this->clippingRect); } painter->setOpacity(this->opacity); for (auto item : this->items) item->render(painter); painter->restore(); } void Overlay::clearItems() { for (auto item : this->items) { delete item; } this->items.clear(); } QList Overlay::getItems() { return this->items; } bool Overlay::getHidden() { return this->hidden; } void Overlay::setHidden(bool hidden) { this->hidden = hidden; } int Overlay::getOpacity() { return this->opacity * 100; } void Overlay::setOpacity(int opacity) { if (opacity < 0 || opacity > 100) { logError(QString("Invalid overlay opacity '%1', must be in range 0-100").arg(opacity)); return; } this->opacity = static_cast(opacity) / 100; } int Overlay::getX() { return this->x; } int Overlay::getY() { return this->y; } void Overlay::setX(int x) { this->x = x; } void Overlay::setY(int y) { this->y = y; } qreal Overlay::getHScale() { return this->hScale; } qreal Overlay::getVScale() { return this->vScale; } void Overlay::setHScale(qreal scale) { this->hScale = scale; } void Overlay::setVScale(qreal scale) { this->vScale = scale; } int Overlay::getAngle() { return this->angle; } void Overlay::setAngle(int angle) { this->angle = angle; this->clampAngle(); } void Overlay::rotate(int degrees) { this->angle += degrees; this->clampAngle(); } void Overlay::clampAngle() { // transform.rotate would handle this already, but we only // want to report angles 0-359 for Overlay::getAngle this->angle %= 360; if (this->angle < 0) this->angle += 360; } void Overlay::setClippingRect(QRectF rect) { if (this->clippingRect) { delete this->clippingRect; } this->clippingRect = new QRectF(rect); } void Overlay::clearClippingRect() { if (this->clippingRect) { delete this->clippingRect; } this->clippingRect = nullptr; } void Overlay::setPosition(int x, int y) { this->x = x; this->y = y; } void Overlay::move(int deltaX, int deltaY) { this->x += deltaX; this->y += deltaY; } QColor Overlay::getColor(QString colorStr) { if (colorStr.isEmpty()) colorStr = "transparent"; QColor color = QColor(colorStr); if (!color.isValid()) { logWarn(QString("Invalid overlay color \"%1\". Colors can be in the format \"#RRGGBB\" or \"#AARRGGBB\"").arg(colorStr)); color = QColor("transparent"); } return color; } void Overlay::addText(const QString text, int x, int y, QString colorStr, int fontSize) { this->items.append(new OverlayText(text, x, y, getColor(colorStr), fontSize)); } bool Overlay::addRect(int x, int y, int width, int height, QString borderColorStr, QString fillColorStr, int rounding) { if (rounding < 0 || rounding > 100) { logError(QString("Invalid rectangle rounding '%1', must be in range 0-100").arg(rounding)); return false; } QPainterPath path; path.addRoundedRect(QRectF(x, y, width, height), rounding, rounding, Qt::RelativeSize); this->items.append(new OverlayPath(path, getColor(borderColorStr), getColor(fillColorStr))); return true; } bool Overlay::addPath(QList xCoords, QList yCoords, QString borderColorStr, QString fillColorStr) { int numPoints = qMin(xCoords.length(), yCoords.length()); if (numPoints < 2) { logError("Overlay path must have at least two points."); return false; } QPainterPath path; path.moveTo(xCoords.at(0), yCoords.at(0)); for (int i = 1; i < numPoints; i++) path.lineTo(xCoords.at(i), yCoords.at(i)); this->items.append(new OverlayPath(path, getColor(borderColorStr), getColor(fillColorStr))); return true; } bool Overlay::addImage(int x, int y, QString filepath, bool useCache, int width, int height, int xOffset, int yOffset, qreal hScale, qreal vScale, QList palette, bool setTransparency) { QImage image = useCache ? Scripting::getImage(filepath) : QImage(filepath); if (image.isNull()) { logError(QString("Failed to load image '%1'").arg(filepath)); return false; } int fullWidth = image.width(); int fullHeight = image.height(); // Negative values used as an indicator for "use full dimension" if (width <= 0) width = fullWidth; if (height <= 0) height = fullHeight; if (xOffset < 0) xOffset = 0; if (yOffset < 0) yOffset = 0; if (width + xOffset > fullWidth || height + yOffset > fullHeight) { logError(QString("%1x%2 image starting at (%3,%4) exceeds the image size for '%5'") .arg(width) .arg(height) .arg(xOffset) .arg(yOffset) .arg(filepath)); return false; } // Get specified subset of image if (width != fullWidth || height != fullHeight) image = image.copy(xOffset, yOffset, width, height); if (hScale != 1 || vScale != 1) image = image.transformed(QTransform().scale(hScale, vScale)); for (int i = 0; i < palette.size(); i++) image.setColor(i, palette.at(i)); if (setTransparency) image.setColor(0, qRgba(0, 0, 0, 0)); this->items.append(new OverlayImage(x, y, image)); return true; } bool Overlay::addImage(int x, int y, QImage image) { if (image.isNull()) { logError(QString("Failed to load custom image")); return false; } this->items.append(new OverlayImage(x, y, image)); return true; }