2021-05-24 07:25:56 +00:00
|
|
|
|
/*
|
|
|
|
|
SPDX-FileCopyrightText: 2015 Laurent Montel <montel@kde.org>
|
|
|
|
|
SPDX-FileCopyrightText: 2015 Albert Astals Cid <aacid@kde.org>
|
|
|
|
|
|
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
*/
|
2015-08-22 14:00:04 +00:00
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
#include "drawingtoolactions.h"
|
2015-08-22 14:00:04 +00:00
|
|
|
|
|
2022-01-26 16:27:42 +00:00
|
|
|
|
#include "gui/debug_ui.h"
|
2015-08-22 14:00:04 +00:00
|
|
|
|
#include "settings.h"
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
#include <KActionCollection>
|
2015-08-22 14:00:04 +00:00
|
|
|
|
#include <KLocalizedString>
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
#include <QAction>
|
2020-04-19 00:27:55 +00:00
|
|
|
|
#include <QIconEngine>
|
2015-08-22 14:00:04 +00:00
|
|
|
|
#include <QPainter>
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
class ColorAction : public QAction
|
2015-08-22 14:00:04 +00:00
|
|
|
|
{
|
2016-10-29 14:32:24 +00:00
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
2015-08-22 14:00:04 +00:00
|
|
|
|
public:
|
2015-08-22 20:15:32 +00:00
|
|
|
|
explicit ColorAction(KActionCollection *parent)
|
|
|
|
|
: QAction(parent)
|
2015-08-22 14:00:04 +00:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setColor(const QColor &color)
|
|
|
|
|
{
|
2020-04-19 00:27:55 +00:00
|
|
|
|
setIcon(QIcon(new ColorActionIconEngine(color)));
|
2015-08-22 14:00:04 +00:00
|
|
|
|
}
|
2020-04-19 00:27:55 +00:00
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
class ColorActionIconEngine : public QIconEngine
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
explicit ColorActionIconEngine(const QColor &color)
|
|
|
|
|
: m_color(color)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ColorActionIconEngine(const ColorActionIconEngine &) = delete;
|
|
|
|
|
ColorActionIconEngine &operator=(const ColorActionIconEngine &) = delete;
|
|
|
|
|
|
|
|
|
|
// No one needs clone(), but it’s pure virtual
|
|
|
|
|
QIconEngine *clone() const override
|
|
|
|
|
{
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override
|
|
|
|
|
{
|
|
|
|
|
QPixmap pixmap(size);
|
|
|
|
|
pixmap.fill(Qt::transparent);
|
|
|
|
|
Q_ASSERT(pixmap.hasAlphaChannel());
|
|
|
|
|
|
|
|
|
|
QPainter painter(&pixmap);
|
|
|
|
|
paint(&painter, QRect(QPoint(0, 0), size), mode, state);
|
|
|
|
|
return pixmap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void paint(QPainter *painter, const QRect &rect, QIcon::Mode mode, QIcon::State state) override
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(mode)
|
|
|
|
|
|
|
|
|
|
// Assume that rect is square and at position (0, 0)
|
|
|
|
|
int squareSize = rect.height() * 0.8;
|
|
|
|
|
int squareOffset = (rect.height() - squareSize) / 2;
|
|
|
|
|
|
|
|
|
|
painter->fillRect(squareOffset, squareOffset, squareSize, squareSize, m_color);
|
|
|
|
|
|
|
|
|
|
if (state == QIcon::On) {
|
|
|
|
|
QFont checkmarkFont = painter->font();
|
|
|
|
|
checkmarkFont.setPixelSize(squareSize * 0.9);
|
|
|
|
|
painter->setFont(checkmarkFont);
|
|
|
|
|
|
|
|
|
|
const int lightness = ((m_color.red() * 299) + (m_color.green() * 587) + (m_color.blue() * 114)) / 1000;
|
|
|
|
|
painter->setPen(lightness < 128 ? Qt::white : Qt::black);
|
|
|
|
|
|
|
|
|
|
painter->drawText(QRect(squareOffset, squareOffset, squareSize, squareSize), Qt::AlignCenter, QStringLiteral("\u2713"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
QColor m_color;
|
|
|
|
|
};
|
2015-08-22 14:00:04 +00:00
|
|
|
|
};
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
DrawingToolActions::DrawingToolActions(KActionCollection *parent)
|
|
|
|
|
: QObject(parent)
|
2015-08-22 14:00:04 +00:00
|
|
|
|
{
|
|
|
|
|
loadTools();
|
2015-08-22 20:15:32 +00:00
|
|
|
|
}
|
2015-08-22 14:00:04 +00:00
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
DrawingToolActions::~DrawingToolActions()
|
|
|
|
|
{
|
2015-08-22 14:00:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
QList<QAction *> DrawingToolActions::actions() const
|
|
|
|
|
{
|
|
|
|
|
return m_actions;
|
|
|
|
|
}
|
2015-08-22 14:00:04 +00:00
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
void DrawingToolActions::reparseConfig()
|
2015-08-22 14:00:04 +00:00
|
|
|
|
{
|
2015-08-22 20:15:32 +00:00
|
|
|
|
qDeleteAll(m_actions);
|
|
|
|
|
m_actions.clear();
|
|
|
|
|
loadTools();
|
2015-08-22 14:00:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
void DrawingToolActions::actionTriggered()
|
2015-08-22 14:00:04 +00:00
|
|
|
|
{
|
2015-08-22 20:15:32 +00:00
|
|
|
|
QAction *action = qobject_cast<QAction *>(sender());
|
2020-07-10 22:15:05 +00:00
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
if (action) {
|
|
|
|
|
if (action->isChecked()) {
|
2023-12-19 08:58:22 +00:00
|
|
|
|
for (QAction *btn : std::as_const(m_actions)) {
|
2015-08-22 20:15:32 +00:00
|
|
|
|
if (action != btn) {
|
2015-08-22 14:00:04 +00:00
|
|
|
|
btn->setChecked(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-18 21:35:45 +00:00
|
|
|
|
Q_EMIT changeEngine(action->property("__document").value<QDomElement>());
|
2015-08-22 14:00:04 +00:00
|
|
|
|
} else {
|
2022-03-18 21:35:45 +00:00
|
|
|
|
Q_EMIT changeEngine(QDomElement());
|
2015-08-22 14:00:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
void DrawingToolActions::loadTools()
|
2015-08-22 14:00:04 +00:00
|
|
|
|
{
|
|
|
|
|
const QStringList drawingTools = Okular::Settings::drawingTools();
|
|
|
|
|
|
2023-08-10 22:47:57 +00:00
|
|
|
|
QDomDocument main;
|
|
|
|
|
QDomElement drawingDefinition = main.createElement(QStringLiteral("drawingTools"));
|
2019-12-09 13:39:47 +00:00
|
|
|
|
for (const QString &drawingXml : drawingTools) {
|
2015-08-22 14:00:04 +00:00
|
|
|
|
QDomDocument entryParser;
|
|
|
|
|
if (entryParser.setContent(drawingXml)) {
|
2023-08-10 22:47:57 +00:00
|
|
|
|
drawingDefinition.appendChild(main.importNode(entryParser.documentElement(), true));
|
2015-08-22 14:00:04 +00:00
|
|
|
|
} else {
|
|
|
|
|
qCWarning(OkularUiDebug) << "Skipping malformed quick selection XML in QuickSelectionTools setting";
|
2022-03-08 10:10:43 +00:00
|
|
|
|
}
|
2015-08-22 14:00:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the AnnotationToolItems from the XML dom tree
|
|
|
|
|
QDomNode drawingDescription = drawingDefinition.firstChild();
|
|
|
|
|
while (drawingDescription.isElement()) {
|
|
|
|
|
const QDomElement toolElement = drawingDescription.toElement();
|
2015-10-29 12:37:11 +00:00
|
|
|
|
if (toolElement.tagName() == QLatin1String("tool")) {
|
2015-08-22 20:15:32 +00:00
|
|
|
|
QString tooltip;
|
2015-08-22 14:00:04 +00:00
|
|
|
|
QString width;
|
|
|
|
|
QString colorStr;
|
|
|
|
|
QString opacity;
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
const QString name = toolElement.attribute(QStringLiteral("name"));
|
|
|
|
|
if (toolElement.attribute(QStringLiteral("default"), QStringLiteral("false")) == QLatin1String("true")) {
|
|
|
|
|
tooltip = i18n(name.toLatin1().constData());
|
|
|
|
|
} else {
|
|
|
|
|
tooltip = name;
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-29 12:37:11 +00:00
|
|
|
|
const QDomNodeList engineNodeList = toolElement.elementsByTagName(QStringLiteral("engine"));
|
2015-08-22 14:00:04 +00:00
|
|
|
|
if (engineNodeList.size() > 0) {
|
|
|
|
|
const QDomElement engineEl = engineNodeList.item(0).toElement();
|
|
|
|
|
if (engineEl.hasAttribute(QStringLiteral("color"))) {
|
|
|
|
|
colorStr = engineEl.attribute(QStringLiteral("color"));
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-29 12:37:11 +00:00
|
|
|
|
const QDomNodeList annotationList = engineEl.elementsByTagName(QStringLiteral("annotation"));
|
2015-08-22 14:00:04 +00:00
|
|
|
|
if (annotationList.size() > 0) {
|
|
|
|
|
const QDomElement annotationEl = annotationList.item(0).toElement();
|
|
|
|
|
if (annotationEl.hasAttribute(QStringLiteral("width"))) {
|
|
|
|
|
width = annotationEl.attribute(QStringLiteral("width"));
|
|
|
|
|
opacity = annotationEl.attribute(QStringLiteral("opacity"), QStringLiteral("1.0"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-10 22:47:57 +00:00
|
|
|
|
QDomDocument engine(QStringLiteral("engine"));
|
|
|
|
|
QDomElement root = engine.createElement(QStringLiteral("engine"));
|
2015-08-22 14:00:04 +00:00
|
|
|
|
root.setAttribute(QStringLiteral("color"), colorStr);
|
2023-08-10 22:47:57 +00:00
|
|
|
|
engine.appendChild(root);
|
|
|
|
|
QDomElement annElem = engine.createElement(QStringLiteral("annotation"));
|
2015-08-22 14:00:04 +00:00
|
|
|
|
root.appendChild(annElem);
|
|
|
|
|
annElem.setAttribute(QStringLiteral("type"), QStringLiteral("Ink"));
|
|
|
|
|
annElem.setAttribute(QStringLiteral("color"), colorStr);
|
|
|
|
|
annElem.setAttribute(QStringLiteral("width"), width);
|
|
|
|
|
annElem.setAttribute(QStringLiteral("opacity"), opacity);
|
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
const QString text = i18n("Drawing Tool: %1", tooltip);
|
2015-08-10 11:05:12 +00:00
|
|
|
|
createToolAction(text, tooltip, colorStr, root);
|
2015-08-22 14:00:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawingDescription = drawingDescription.nextSibling();
|
|
|
|
|
}
|
2015-08-10 11:05:12 +00:00
|
|
|
|
|
|
|
|
|
// add erasure action
|
|
|
|
|
{
|
2023-08-10 22:47:57 +00:00
|
|
|
|
QDomDocument engine(QStringLiteral("engine"));
|
|
|
|
|
QDomElement root = engine.createElement(QStringLiteral("engine"));
|
2015-08-10 11:05:12 +00:00
|
|
|
|
root.setAttribute(QStringLiteral("color"), QStringLiteral("transparent"));
|
|
|
|
|
root.setAttribute(QStringLiteral("compositionMode"), QStringLiteral("clear"));
|
2023-08-10 22:47:57 +00:00
|
|
|
|
engine.appendChild(root);
|
|
|
|
|
QDomElement annElem = engine.createElement(QStringLiteral("annotation"));
|
2015-08-10 11:05:12 +00:00
|
|
|
|
root.appendChild(annElem);
|
|
|
|
|
annElem.setAttribute(QStringLiteral("type"), QStringLiteral("Ink"));
|
|
|
|
|
annElem.setAttribute(QStringLiteral("color"), QStringLiteral("transparent"));
|
|
|
|
|
annElem.setAttribute(QStringLiteral("width"), 20);
|
2020-07-10 22:15:05 +00:00
|
|
|
|
|
2015-08-10 11:05:12 +00:00
|
|
|
|
KActionCollection *ac = static_cast<KActionCollection *>(parent());
|
|
|
|
|
QAction *action = new QAction(ac);
|
|
|
|
|
action->setText(i18n("Eraser"));
|
|
|
|
|
action->setToolTip(i18n("Eraser"));
|
|
|
|
|
action->setCheckable(true);
|
2015-10-29 12:37:11 +00:00
|
|
|
|
action->setIcon(QIcon::fromTheme(QStringLiteral("draw-eraser")));
|
2015-08-10 11:05:12 +00:00
|
|
|
|
action->setProperty("__document", QVariant::fromValue<QDomElement>(root));
|
2020-07-10 22:15:05 +00:00
|
|
|
|
|
2015-08-10 11:05:12 +00:00
|
|
|
|
m_actions.append(action);
|
2020-07-10 22:15:05 +00:00
|
|
|
|
|
2015-10-29 12:37:11 +00:00
|
|
|
|
ac->addAction(QStringLiteral("presentation_drawing_eraser"), action);
|
2020-07-10 22:15:05 +00:00
|
|
|
|
|
2015-08-10 11:05:12 +00:00
|
|
|
|
connect(action, &QAction::triggered, this, &DrawingToolActions::actionTriggered);
|
|
|
|
|
}
|
2015-08-22 14:00:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-10 11:05:12 +00:00
|
|
|
|
void DrawingToolActions::createToolAction(const QString &text, const QString &toolName, const QString &colorName, const QDomElement &root)
|
2015-08-22 14:00:04 +00:00
|
|
|
|
{
|
2015-08-22 20:15:32 +00:00
|
|
|
|
KActionCollection *ac = static_cast<KActionCollection *>(parent());
|
|
|
|
|
ColorAction *action = new ColorAction(ac);
|
|
|
|
|
action->setText(text);
|
|
|
|
|
action->setToolTip(toolName);
|
|
|
|
|
action->setCheckable(true);
|
|
|
|
|
action->setColor(QColor(colorName));
|
|
|
|
|
action->setEnabled(false);
|
2015-08-22 14:00:04 +00:00
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
action->setProperty("__document", QVariant::fromValue<QDomElement>(root));
|
2015-08-22 14:00:04 +00:00
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
m_actions.append(action);
|
2015-08-22 14:00:04 +00:00
|
|
|
|
|
2015-10-29 12:37:11 +00:00
|
|
|
|
ac->addAction(QStringLiteral("presentation_drawing_%1").arg(toolName), action);
|
2015-08-22 14:00:04 +00:00
|
|
|
|
|
2015-08-22 20:15:32 +00:00
|
|
|
|
connect(action, &QAction::triggered, this, &DrawingToolActions::actionTriggered);
|
2015-08-22 14:00:04 +00:00
|
|
|
|
}
|
2016-10-29 14:32:24 +00:00
|
|
|
|
|
|
|
|
|
#include "drawingtoolactions.moc"
|