File indexing completed on 2024-05-19 04:35:32
0001 /* 0002 SPDX-FileCopyrightText: 2015 Laurent Montel <montel@kde.org> 0003 SPDX-FileCopyrightText: 2015 Albert Astals Cid <aacid@kde.org> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "drawingtoolactions.h" 0009 0010 #include "gui/debug_ui.h" 0011 #include "settings.h" 0012 0013 #include <KActionCollection> 0014 #include <KLocalizedString> 0015 0016 #include <QAction> 0017 #include <QIconEngine> 0018 #include <QPainter> 0019 0020 class ColorAction : public QAction 0021 { 0022 Q_OBJECT 0023 0024 public: 0025 explicit ColorAction(KActionCollection *parent) 0026 : QAction(parent) 0027 { 0028 } 0029 0030 void setColor(const QColor &color) 0031 { 0032 setIcon(QIcon(new ColorActionIconEngine(color))); 0033 } 0034 0035 protected: 0036 class ColorActionIconEngine : public QIconEngine 0037 { 0038 public: 0039 explicit ColorActionIconEngine(const QColor &color) 0040 : m_color(color) 0041 { 0042 } 0043 0044 ColorActionIconEngine(const ColorActionIconEngine &) = delete; 0045 ColorActionIconEngine &operator=(const ColorActionIconEngine &) = delete; 0046 0047 // No one needs clone(), but it’s pure virtual 0048 QIconEngine *clone() const override 0049 { 0050 return nullptr; 0051 } 0052 0053 QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override 0054 { 0055 QPixmap pixmap(size); 0056 pixmap.fill(Qt::transparent); 0057 Q_ASSERT(pixmap.hasAlphaChannel()); 0058 0059 QPainter painter(&pixmap); 0060 paint(&painter, QRect(QPoint(0, 0), size), mode, state); 0061 return pixmap; 0062 } 0063 0064 void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override 0065 { 0066 Q_UNUSED(mode) 0067 0068 // Assume that rect is square and at position (0, 0) 0069 int squareSize = rect.height() * 0.8; 0070 int squareOffset = (rect.height() - squareSize) / 2; 0071 0072 painter->fillRect(squareOffset, squareOffset, squareSize, squareSize, m_color); 0073 0074 if (state == QIcon::On) { 0075 QFont checkmarkFont = painter->font(); 0076 checkmarkFont.setPixelSize(squareSize * 0.9); 0077 painter->setFont(checkmarkFont); 0078 0079 const int lightness = ((m_color.red() * 299) + (m_color.green() * 587) + (m_color.blue() * 114)) / 1000; 0080 painter->setPen(lightness < 128 ? Qt::white : Qt::black); 0081 0082 painter->drawText(QRect(squareOffset, squareOffset, squareSize, squareSize), Qt::AlignCenter, QStringLiteral("\u2713")); 0083 } 0084 } 0085 0086 protected: 0087 QColor m_color; 0088 }; 0089 }; 0090 0091 DrawingToolActions::DrawingToolActions(KActionCollection *parent) 0092 : QObject(parent) 0093 { 0094 loadTools(); 0095 } 0096 0097 DrawingToolActions::~DrawingToolActions() 0098 { 0099 } 0100 0101 QList<QAction *> DrawingToolActions::actions() const 0102 { 0103 return m_actions; 0104 } 0105 0106 void DrawingToolActions::reparseConfig() 0107 { 0108 qDeleteAll(m_actions); 0109 m_actions.clear(); 0110 loadTools(); 0111 } 0112 0113 void DrawingToolActions::actionTriggered() 0114 { 0115 QAction *action = qobject_cast<QAction *>(sender()); 0116 0117 if (action) { 0118 if (action->isChecked()) { 0119 for (QAction *btn : std::as_const(m_actions)) { 0120 if (action != btn) { 0121 btn->setChecked(false); 0122 } 0123 } 0124 0125 Q_EMIT changeEngine(action->property("__document").value<QDomElement>()); 0126 } else { 0127 Q_EMIT changeEngine(QDomElement()); 0128 } 0129 } 0130 } 0131 0132 void DrawingToolActions::loadTools() 0133 { 0134 const QStringList drawingTools = Okular::Settings::drawingTools(); 0135 0136 QDomDocument main; 0137 QDomElement drawingDefinition = main.createElement(QStringLiteral("drawingTools")); 0138 for (const QString &drawingXml : drawingTools) { 0139 QDomDocument entryParser; 0140 if (entryParser.setContent(drawingXml)) { 0141 drawingDefinition.appendChild(main.importNode(entryParser.documentElement(), true)); 0142 } else { 0143 qCWarning(OkularUiDebug) << "Skipping malformed quick selection XML in QuickSelectionTools setting"; 0144 } 0145 } 0146 0147 // Create the AnnotationToolItems from the XML dom tree 0148 QDomNode drawingDescription = drawingDefinition.firstChild(); 0149 while (drawingDescription.isElement()) { 0150 const QDomElement toolElement = drawingDescription.toElement(); 0151 if (toolElement.tagName() == QLatin1String("tool")) { 0152 QString tooltip; 0153 QString width; 0154 QString colorStr; 0155 QString opacity; 0156 0157 const QString name = toolElement.attribute(QStringLiteral("name")); 0158 if (toolElement.attribute(QStringLiteral("default"), QStringLiteral("false")) == QLatin1String("true")) { 0159 tooltip = i18n(name.toLatin1().constData()); 0160 } else { 0161 tooltip = name; 0162 } 0163 0164 const QDomNodeList engineNodeList = toolElement.elementsByTagName(QStringLiteral("engine")); 0165 if (engineNodeList.size() > 0) { 0166 const QDomElement engineEl = engineNodeList.item(0).toElement(); 0167 if (engineEl.hasAttribute(QStringLiteral("color"))) { 0168 colorStr = engineEl.attribute(QStringLiteral("color")); 0169 } 0170 0171 const QDomNodeList annotationList = engineEl.elementsByTagName(QStringLiteral("annotation")); 0172 if (annotationList.size() > 0) { 0173 const QDomElement annotationEl = annotationList.item(0).toElement(); 0174 if (annotationEl.hasAttribute(QStringLiteral("width"))) { 0175 width = annotationEl.attribute(QStringLiteral("width")); 0176 opacity = annotationEl.attribute(QStringLiteral("opacity"), QStringLiteral("1.0")); 0177 } 0178 } 0179 } 0180 0181 QDomDocument engine(QStringLiteral("engine")); 0182 QDomElement root = engine.createElement(QStringLiteral("engine")); 0183 root.setAttribute(QStringLiteral("color"), colorStr); 0184 engine.appendChild(root); 0185 QDomElement annElem = engine.createElement(QStringLiteral("annotation")); 0186 root.appendChild(annElem); 0187 annElem.setAttribute(QStringLiteral("type"), QStringLiteral("Ink")); 0188 annElem.setAttribute(QStringLiteral("color"), colorStr); 0189 annElem.setAttribute(QStringLiteral("width"), width); 0190 annElem.setAttribute(QStringLiteral("opacity"), opacity); 0191 0192 const QString text = i18n("Drawing Tool: %1", tooltip); 0193 createToolAction(text, tooltip, colorStr, root); 0194 } 0195 0196 drawingDescription = drawingDescription.nextSibling(); 0197 } 0198 0199 // add erasure action 0200 { 0201 QDomDocument engine(QStringLiteral("engine")); 0202 QDomElement root = engine.createElement(QStringLiteral("engine")); 0203 root.setAttribute(QStringLiteral("color"), QStringLiteral("transparent")); 0204 root.setAttribute(QStringLiteral("compositionMode"), QStringLiteral("clear")); 0205 engine.appendChild(root); 0206 QDomElement annElem = engine.createElement(QStringLiteral("annotation")); 0207 root.appendChild(annElem); 0208 annElem.setAttribute(QStringLiteral("type"), QStringLiteral("Ink")); 0209 annElem.setAttribute(QStringLiteral("color"), QStringLiteral("transparent")); 0210 annElem.setAttribute(QStringLiteral("width"), 20); 0211 0212 KActionCollection *ac = static_cast<KActionCollection *>(parent()); 0213 QAction *action = new QAction(ac); 0214 action->setText(i18n("Eraser")); 0215 action->setToolTip(i18n("Eraser")); 0216 action->setCheckable(true); 0217 action->setIcon(QIcon::fromTheme(QStringLiteral("draw-eraser"))); 0218 action->setProperty("__document", QVariant::fromValue<QDomElement>(root)); 0219 0220 m_actions.append(action); 0221 0222 ac->addAction(QStringLiteral("presentation_drawing_eraser"), action); 0223 0224 connect(action, &QAction::triggered, this, &DrawingToolActions::actionTriggered); 0225 } 0226 } 0227 0228 void DrawingToolActions::createToolAction(const QString &text, const QString &toolName, const QString &colorName, const QDomElement &root) 0229 { 0230 KActionCollection *ac = static_cast<KActionCollection *>(parent()); 0231 ColorAction *action = new ColorAction(ac); 0232 action->setText(text); 0233 action->setToolTip(toolName); 0234 action->setCheckable(true); 0235 action->setColor(QColor(colorName)); 0236 action->setEnabled(false); 0237 0238 action->setProperty("__document", QVariant::fromValue<QDomElement>(root)); 0239 0240 m_actions.append(action); 0241 0242 ac->addAction(QStringLiteral("presentation_drawing_%1").arg(toolName), action); 0243 0244 connect(action, &QAction::triggered, this, &DrawingToolActions::actionTriggered); 0245 } 0246 0247 #include "drawingtoolactions.moc"