/* * graphicelements.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */ #include "StdInc.h" #include "graphicelements.h" #include #include "../../lib/constants/EntityIdentifiers.h" #include "../../lib/rmg/CRmgTemplate.h" QDomElement CardItem::getElementById(const QDomDocument& doc, const QString& id) { QDomElement root = doc.documentElement(); std::function findById = [&](const QDomElement& elem) -> QDomElement { if (elem.attribute("id") == id) return elem; QDomElement child = elem.firstChildElement(); while (!child.isNull()) { QDomElement found = findById(child); if (!found.isNull()) return found; child = child.nextSiblingElement(); } return QDomElement(); }; return findById(root); } bool isBlackTextNeeded(const QColor& bg) { int r = bg.red(); int g = bg.green(); int b = bg.blue(); double luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255; return luminance > 0.5; } CardItem::CardItem(): selectCallback(nullptr), posChangeCallback(nullptr), useBlackText(false), mousePressed(false) { QFile file(":/icons/templateSquare.svg"); file.open(QIODevice::ReadOnly); QByteArray data = file.readAll(); doc.setContent(data); updateContent(); } void CardItem::setSelectCallback(std::function func) { selectCallback = func; } void CardItem::setPosChangeCallback(std::function func) { posChangeCallback = func; } void CardItem::updateContent() { setSharedRenderer(new QSvgRenderer(doc.toByteArray())); } void CardItem::setFillColor(QColor color) { auto squareElem = getElementById(doc, "rect"); squareElem.setAttribute("style", squareElem.attribute("style").replace(QRegularExpression("fill:.*?;"), "fill:" + color.name() + ";")); useBlackText = isBlackTextNeeded(color); } void CardItem::setMultiFillColor(QColor color1, QColor color2) { auto squareElem = getElementById(doc, "rect"); squareElem.setAttribute("style", squareElem.attribute("style").replace(QRegularExpression("fill:.*?;"), "fill:url(#gradientExtra);")); auto gradientStopElem1 = getElementById(doc, "gradientExtraColorStop1"); auto gradientStopElem2 = getElementById(doc, "gradientExtraColorStop2"); auto gradientStopElem3 = getElementById(doc, "gradientExtraColorStop3"); auto gradientStopElem4 = getElementById(doc, "gradientExtraColorStop4"); auto gradientStopElem5 = getElementById(doc, "gradientExtraColorStop5"); gradientStopElem1.setAttribute("style", gradientStopElem1.attribute("style").replace(QRegularExpression("stop-color:.*?;"), "stop-color:" + color1.name() + ";")); gradientStopElem2.setAttribute("style", gradientStopElem2.attribute("style").replace(QRegularExpression("stop-color:.*?;"), "stop-color:" + color2.name() + ";")); gradientStopElem3.setAttribute("style", gradientStopElem3.attribute("style").replace(QRegularExpression("stop-color:.*?;"), "stop-color:" + color1.name() + ";")); gradientStopElem4.setAttribute("style", gradientStopElem4.attribute("style").replace(QRegularExpression("stop-color:.*?;"), "stop-color:" + color2.name() + ";")); gradientStopElem5.setAttribute("style", gradientStopElem5.attribute("style").replace(QRegularExpression("stop-color:.*?;"), "stop-color:" + color1.name() + ";")); useBlackText = isBlackTextNeeded(color1); } void CardItem::setPlayerColor(PlayerColor color) { std::map> colors = { { PlayerColor(0), { "#F80000", "#920000" } }, //red { PlayerColor(1), { "#0000F8", "#000092" } }, //blue { PlayerColor(2), { "#9B7251", "#35271C" } }, //tan { PlayerColor(3), { "#00FC00", "#009600" } }, //green { PlayerColor(4), { "#F88000", "#924B00" } }, //orange { PlayerColor(5), { "#F800F8", "#920092" } }, //purple { PlayerColor(6), { "#00FCF8", "#009694" } }, //teal { PlayerColor(7), { "#C07888", "#5A3840" } }, //pink }; auto squareElem = getElementById(doc, "rect"); squareElem.setAttribute("style", squareElem.attribute("style").replace(QRegularExpression("fill:.*?;"), "fill:url(#gradientPlayer);")); auto gradientStopElem1 = getElementById(doc, "gradientPlayerColorStop1"); auto gradientStopElem2 = getElementById(doc, "gradientPlayerColorStop2"); gradientStopElem1.setAttribute("style", gradientStopElem1.attribute("style").replace(QRegularExpression("stop-color:.*?;"), "stop-color:" + colors[color].first + ";")); gradientStopElem2.setAttribute("style", gradientStopElem2.attribute("style").replace(QRegularExpression("stop-color:.*?;"), "stop-color:" + colors[color].second + ";")); useBlackText = isBlackTextNeeded(QColor(colors[color].first)); } void CardItem::setJunction(bool val) { auto squareElem = getElementById(doc, "rectJunction"); squareElem.setAttribute("style", squareElem.attribute("style").replace(QRegularExpression("stroke-opacity:.*?;"), "stroke-opacity:" + QString::fromStdString(val ? "0.3" : "0.0") + ";")); } void CardItem::setId(int val) { auto textIdElem = getElementById(doc, "textId"); textIdElem.setAttribute("style", textIdElem.attribute("style").replace(QRegularExpression("fill:.*?;"), "fill:" + QColor(useBlackText ? Qt::black : Qt::white).name() + ";")); textIdElem.firstChild().setNodeValue(QString::number(val)); id = val; } int CardItem::getId() { return id; } void CardItem::setResAmount(GameResID res, int val) { std::map names = { { GameResID::WOOD, "Wood" }, { GameResID::ORE, "Ore" }, { GameResID::MERCURY, "Mercury" }, { GameResID::SULFUR, "Sulfur" }, { GameResID::CRYSTAL, "Crystal" }, { GameResID::GEMS, "Gems" }, { GameResID::GOLD, "Gold" }, }; auto textElem = getElementById(doc, "text" + names[res]); textElem.setAttribute("style", textElem.attribute("style").replace(QRegularExpression("fill:.*?;"), "fill:" + QColor(useBlackText ? Qt::black : Qt::white).name() + ";")); textElem.firstChild().setNodeValue(val ? QString::number(val) : ""); auto iconElem = getElementById(doc, "icon" + names[res]); iconElem.setAttribute("opacity", val ? "1.0" : "0.1"); } void CardItem::setChestValue(int val) { auto textElem = getElementById(doc, "textChest"); textElem.setAttribute("style", textElem.attribute("style").replace(QRegularExpression("fill:.*?;"), "fill:" + QColor(useBlackText ? Qt::black : Qt::white).name() + ";")); textElem.firstChild().setNodeValue(val ? QString::number(val) : ""); auto iconElem = getElementById(doc, "iconChest"); iconElem.setAttribute("opacity", val ? "1.0" : "0.1"); } void CardItem::setSword(EMonsterStrength::EMonsterStrength val) { int level = 0; if(val == EMonsterStrength::ZONE_WEAK || val == EMonsterStrength::GLOBAL_WEAK) level = 1; else if(val == EMonsterStrength::ZONE_NORMAL || val == EMonsterStrength::GLOBAL_NORMAL) level = 2; else if(val == EMonsterStrength::ZONE_STRONG || val == EMonsterStrength::GLOBAL_STRONG) level = 3; getElementById(doc, "iconSword1").setAttribute("opacity", level > 0 ? "1.0" : "0.1"); getElementById(doc, "iconSword2").setAttribute("opacity", level > 1 ? "1.0" : "0.1"); getElementById(doc, "iconSword3").setAttribute("opacity", level > 2 ? "1.0" : "0.1"); } void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { if(event->button() == Qt::LeftButton) { // set element in grid double xx = x() + (boundingRect().width() / 2); double yy = y() + (boundingRect().height() / 2); xx = GRID_SIZE * round(xx / GRID_SIZE); yy = GRID_SIZE * round(yy / GRID_SIZE); setPos(xx - (boundingRect().width() / 2), yy - (boundingRect().height() / 2)); } QGraphicsSvgItem::mouseReleaseEvent(event); if(posChangeCallback) posChangeCallback(pos()); mousePressed = false; } void CardItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { QGraphicsSvgItem::mousePressEvent(event); mousePressed = true; } QVariant CardItem::itemChange(GraphicsItemChange change, const QVariant &value) { if(change == ItemSelectedHasChanged && selectCallback) selectCallback(isSelected()); else if(change == ItemPositionHasChanged && posChangeCallback && mousePressed) posChangeCallback(pos()); return QGraphicsSvgItem::itemChange(change, value); } LineItem::LineItem(): clickCallback(nullptr) { setZValue(-2); for(int i = 0; i < 10; i++) // render multiple times to increase outline effect { auto tmpTextItem = new QGraphicsTextItem(this); tmpTextItem->setZValue(-1); QFont font; font.setPointSize(18); tmpTextItem->setFont(font); QGraphicsDropShadowEffect *shadowEffect = new QGraphicsDropShadowEffect(); shadowEffect->setBlurRadius(10); shadowEffect->setEnabled(true); shadowEffect->setOffset(0, 0); shadowEffect->setColor(Qt::black); tmpTextItem->setGraphicsEffect(shadowEffect); tmpTextItem->setDefaultTextColor(Qt::white); textItem.push_back(tmpTextItem); } } void LineItem::setLineToolTip(const QString &toolTip) { for(auto & tmpTextItem : textItem) tmpTextItem->setToolTip(toolTip); setToolTip(toolTip); } void LineItem::setClickCallback(std::function func) { clickCallback = func; } void LineItem::setText(QString text) { for(auto & tmpTextItem : textItem) { tmpTextItem->setPlainText(text); QRectF lineRect = boundingRect(); QRectF textRect = tmpTextItem->boundingRect(); tmpTextItem->setPos(QPointF(lineRect.x() + (lineRect.width() / 2) - (textRect.width() / 2), lineRect.y() + (lineRect.height() / 2) - (textRect.height() / 2))); } } void LineItem::setId(int val) { id = val; } int LineItem::getId() { return id; } void LineItem::mousePressEvent(QGraphicsSceneMouseEvent *event) { if(event->button() == Qt::LeftButton && clickCallback) clickCallback(); QGraphicsLineItem::mousePressEvent(event); }