Commit 34708565 authored by David Hurka's avatar David Hurka 🐬
Browse files

Add Constrain Angle action for annotation tools, alternative to pressing Shift

This adds a KToggleAction which sets annotation tools to constrain angle mode.
It provides an alternative user interface to the Shift button, which is used to constrain angles since MR !210.
The action and the Shift button are XOR-ed, i. e. if constrain angle mode is activated, pressing Shift temporarily disables it.

The action state is remembered accross sessions, for consistency with most other actions. It should be difficult to check this action without knowing of its existence, since it is not in any toolbar or menu, just in the action collection.

The meaning of AnnotatorEngine::Modifiers was generalized a bit, moving the responsibility about whether to constrain angles back to PageViewAnnotator, because AnnotatorEngine does not know about the action.

FEATURE: 353560
FIXED-IN: 1.11
parent bba13ee5
......@@ -1171,13 +1171,10 @@ Context menu actions like Rename Bookmarks etc.)
</tgroup>
</informaltable>
<para>
The contents of the annotating toolbar can be configured using the <link linkend="configannotations">Annotations page of &okular; configuration dialog</link>. This page can be opened with &RMB; clicking on the annotating toolbar then choosing <guimenuitem>Configure Annotations...</guimenuitem> from the context menu.
</para>
<para>
With a single &LMB; click on an annotation tool button you can use a tool once.
If you &eg; want to highlight all important parts of a text, activate that tool
permanently by double clicking on the tool button.
Press the <keycap>Esc</keycap> key or click the tool button again to leave the permanent mode.
By pressing <keycap>Shift</keycap> you can constrain the angle of line and polygon annotations to 15° steps, and the ratio of shape annotations (&eg; Rectangle, Ellipse) to 1:1. You can also get a toolbar button from <ulink url="help:/fundamentals/config.html#toolbars">Configure Toolbars...</ulink>.
</para>
<para>
The contents of the <guilabel>Quick Annotations</guilabel> menu can be configured using the <link linkend="configannotations">Annotations page of &okular; configuration dialog</link>. This page can be opened by clicking <guilabel>Quick Annotations</guilabel> button, then choosing <guimenuitem>Configure Annotations...</guimenuitem> from the pop-up menu.
</para>
<note>
<para>
......
......@@ -52,6 +52,7 @@ public:
, aStamp(nullptr)
, aAddToQuickTools(nullptr)
, aContinuousMode(nullptr)
, aConstrainRatioAndAngle(nullptr)
, aWidth(nullptr)
, aColor(nullptr)
, aInnerColor(nullptr)
......@@ -107,6 +108,7 @@ public:
ToggleActionMenu *aStamp;
QAction *aAddToQuickTools;
KToggleAction *aContinuousMode;
KToggleAction *aConstrainRatioAndAngle;
KSelectAction *aWidth;
KSelectAction *aColor;
KSelectAction *aInnerColor;
......@@ -252,8 +254,10 @@ void AnnotationActionHandlerPrivate::updateConfigActions(const QString &annotTyp
const bool isTypewriter = annotType == QStringLiteral("typewriter");
const bool isInlineNote = annotType == QStringLiteral("note-inline");
const bool isText = isInlineNote || isTypewriter;
const bool isShape = annotType == QStringLiteral("rectangle") || annotType == QStringLiteral("ellipse") || annotType == QStringLiteral("polygon");
const bool isLine = annotType == QStringLiteral("ink") || annotType == QStringLiteral("straight-line");
const bool isPolygon = annotType == QStringLiteral("polygon");
const bool isShape = annotType == QStringLiteral("rectangle") || annotType == QStringLiteral("ellipse") || isPolygon;
const bool isStraightLine = annotType == QStringLiteral("straight-line");
const bool isLine = annotType == QStringLiteral("ink") || isStraightLine;
const bool isStamp = annotType == QStringLiteral("stamp");
if (isTypewriter) {
......@@ -269,6 +273,7 @@ void AnnotationActionHandlerPrivate::updateConfigActions(const QString &annotTyp
aInnerColor->setEnabled(isShape);
aOpacity->setEnabled(isAnnotationSelected);
aFont->setEnabled(isText);
aConstrainRatioAndAngle->setEnabled(isStraightLine || isShape);
aAdvancedSettings->setEnabled(isAnnotationSelected);
// set tooltips
......@@ -279,6 +284,7 @@ void AnnotationActionHandlerPrivate::updateConfigActions(const QString &annotTyp
aOpacity->setToolTip(i18nc("@info:tooltip", "Annotation opacity (No annotation selected)"));
aFont->setToolTip(i18nc("@info:tooltip", "Annotation font (No annotation selected)"));
aAddToQuickTools->setToolTip(i18nc("@info:tooltip", "Add the current annotation to the quick annotations menu (No annotation selected)"));
aConstrainRatioAndAngle->setToolTip(i18nc("@info:tooltip", "Constrain shape ratio to 1:1 or line angle to 15° steps (No annotation selected)"));
aAdvancedSettings->setToolTip(i18nc("@info:tooltip", "Advanced settings for the current annotation tool (No annotation selected)"));
return;
}
......@@ -309,6 +315,14 @@ void AnnotationActionHandlerPrivate::updateConfigActions(const QString &annotTyp
aFont->setToolTip(i18nc("@info:tooltip", "Annotation font (Current annotation has no font)"));
}
if (isStraightLine || isPolygon) {
aConstrainRatioAndAngle->setToolTip(i18nc("@info:tooltip", "Constrain line angle to 15° steps"));
} else if (isShape) {
aConstrainRatioAndAngle->setToolTip(i18nc("@info:tooltip", "Constrain shape ratio to 1:1"));
} else {
aConstrainRatioAndAngle->setToolTip(i18nc("@info:tooltip", "Constrain shape ratio to 1:1 or line angle to 15° steps (Not supported by current annotation)"));
}
aOpacity->setToolTip(i18nc("@info:tooltip", "Annotation opacity"));
aAddToQuickTools->setToolTip(i18nc("@info:tooltip", "Add the current annotation to the quick annotations menu"));
aAdvancedSettings->setToolTip(i18nc("@info:tooltip", "Advanced settings for the current annotation tool"));
......@@ -612,6 +626,11 @@ AnnotationActionHandler::AnnotationActionHandler(PageViewAnnotator *parent, KAct
d->aContinuousMode->setToolTip(i18nc("@info:tooltip", "Keep the annotation tool active after use"));
d->aContinuousMode->setChecked(d->annotator->continuousMode());
// Constrain angle action
d->aConstrainRatioAndAngle =
new KToggleAction(QIcon::fromTheme(QStringLiteral("snap-angle")), i18nc("@action When checked, line annotations are constrained to 15° steps, shape annotations to 1:1 ratio", "Constrain Ratio and Angle of Annotation Tools"), this);
d->aConstrainRatioAndAngle->setChecked(d->annotator->constrainRatioAndAngleActive());
// Annotation settings actions
d->aColor = d->colorPickerAction(AnnotationActionHandlerPrivate::AnnotationColor::Color);
d->aInnerColor = d->colorPickerAction(AnnotationActionHandlerPrivate::AnnotationColor::InnerColor);
......@@ -638,6 +657,7 @@ AnnotationActionHandler::AnnotationActionHandler(PageViewAnnotator *parent, KAct
connect(d->aAddToQuickTools, &QAction::triggered, d->annotator, &PageViewAnnotator::addToQuickAnnotations);
connect(d->aContinuousMode, &QAction::toggled, d->annotator, &PageViewAnnotator::setContinuousMode);
connect(d->aConstrainRatioAndAngle, &QAction::toggled, d->annotator, &PageViewAnnotator::setConstrainRatioAndAngle);
connect(d->aAdvancedSettings, &QAction::triggered, d->annotator, &PageViewAnnotator::slotAdvancedSettings);
connect(d->aFont, &QAction::triggered, std::bind(&AnnotationActionHandlerPrivate::slotSelectAnnotationFont, d));
......@@ -675,6 +695,7 @@ AnnotationActionHandler::AnnotationActionHandler(PageViewAnnotator *parent, KAct
ac->addAction(QStringLiteral("annotation_favorites"), d->aQuickTools);
ac->addAction(QStringLiteral("annotation_bookmark"), d->aAddToQuickTools);
ac->addAction(QStringLiteral("annotation_settings_pin"), d->aContinuousMode);
ac->addAction(QStringLiteral("annotation_constrain_ratio_angle"), d->aConstrainRatioAndAngle);
ac->addAction(QStringLiteral("annotation_settings_width"), d->aWidth);
ac->addAction(QStringLiteral("annotation_settings_color"), d->aColor);
ac->addAction(QStringLiteral("annotation_settings_inner_color"), d->aInnerColor);
......
......@@ -34,7 +34,7 @@ AnnotatorEngine::AnnotatorEngine(const QDomElement &engineElement)
m_annotElement = annElement;
}
void AnnotatorEngine::decodeEvent(const QMouseEvent *mouseEvent, EventType *eventType, Button *button, Modifiers *modifiers)
void AnnotatorEngine::decodeEvent(const QMouseEvent *mouseEvent, EventType *eventType, Button *button)
{
*eventType = AnnotatorEngine::Press;
if (mouseEvent->type() == QEvent::MouseMove)
......@@ -48,11 +48,9 @@ void AnnotatorEngine::decodeEvent(const QMouseEvent *mouseEvent, EventType *even
*button = AnnotatorEngine::Left;
else if (buttonState == Qt::RightButton)
*button = AnnotatorEngine::Right;
modifiers->shift = mouseEvent->modifiers() & Qt::ShiftModifier;
}
void AnnotatorEngine::decodeEvent(const QTabletEvent *tabletEvent, EventType *eventType, Button *button, Modifiers *modifiers)
void AnnotatorEngine::decodeEvent(const QTabletEvent *tabletEvent, EventType *eventType, Button *button)
{
switch (tabletEvent->type()) {
case QEvent::TabletPress:
......@@ -75,8 +73,6 @@ void AnnotatorEngine::decodeEvent(const QTabletEvent *tabletEvent, EventType *ev
Q_ASSERT(false);
break;
}
modifiers->shift = tabletEvent->modifiers() & Qt::ShiftModifier;
}
AnnotatorEngine::~AnnotatorEngine()
......
......@@ -42,8 +42,9 @@ public:
// enum definitions
enum EventType { Press, Move, Release };
enum Button { None, Left, Right };
/** To tell the annotator engine about modifier keys and other special wishes */
struct Modifiers {
bool shift;
bool constrainRatioAndAngle; ///< Whether the engine shall snap to certain angles, if supported.
};
// perform operations
......@@ -63,8 +64,8 @@ public:
m_item = item;
}
static void decodeEvent(const QMouseEvent *mouseEvent, EventType *eventType, Button *button, Modifiers *modifiers);
static void decodeEvent(const QTabletEvent *tabletEvent, EventType *eventType, Button *button, Modifiers *modifiers);
static void decodeEvent(const QMouseEvent *mouseEvent, EventType *eventType, Button *button);
static void decodeEvent(const QTabletEvent *tabletEvent, EventType *eventType, Button *button);
virtual QCursor cursor() const;
......
......@@ -99,8 +99,8 @@ public:
} else
return QRect();
// shift button: enforce 1:1 form factor (e.g. circle or square)
if (modifiers.shift) {
// Constrain to 1:1 form factor (e.g. circle or square)
if (modifiers.constrainRatioAndAngle) {
double side = qMin(qAbs(nX - startpoint.x) * xScale, qAbs(nY - startpoint.y) * yScale);
nX = qBound(startpoint.x - side / xScale, nX, startpoint.x + side / xScale);
nY = qBound(startpoint.y - side / yScale, nY, startpoint.y + side / yScale);
......@@ -350,8 +350,8 @@ public:
// if ( button != Left )
// return rect;
// shift button: constrain to 15° steps
if (modifiers.shift && !points.isEmpty()) {
// Constrain to 15° steps, except first point of course.
if (modifiers.constrainRatioAndAngle && !points.isEmpty()) {
const Okular::NormalizedPoint constrainedPoint = constrainAngle(points.constLast(), nX, nY, xScale, yScale, M_PI / 12.);
nX = constrainedPoint.x;
nY = constrainedPoint.y;
......@@ -707,6 +707,7 @@ PageViewAnnotator::PageViewAnnotator(PageView *parent, Okular::Document *storage
, m_toolsDefinition(nullptr)
, m_quickToolsDefinition(nullptr)
, m_continuousMode(true)
, m_constrainRatioAndAngle(false)
, m_lastToolID(-1)
, m_lockedItem(nullptr)
{
......@@ -840,7 +841,10 @@ QRect PageViewAnnotator::routeMouseEvent(QMouseEvent *e, PageViewItem *item)
AnnotatorEngine::Modifiers modifiers;
// figure out the event type and button
AnnotatorEngine::decodeEvent(e, &eventType, &button, &modifiers);
AnnotatorEngine::decodeEvent(e, &eventType, &button);
// Constrain angle if action checked XOR shift button pressed.
modifiers.constrainRatioAndAngle = (bool(constrainRatioAndAngleActive()) != bool(e->modifiers() & Qt::ShiftModifier));
return performRouteMouseOrTabletEvent(eventType, button, modifiers, e->localPos(), item);
}
......@@ -859,7 +863,10 @@ QRect PageViewAnnotator::routeTabletEvent(QTabletEvent *e, PageViewItem *item, c
AnnotatorEngine::Modifiers modifiers;
// figure out the event type and button
AnnotatorEngine::decodeEvent(e, &eventType, &button, &modifiers);
AnnotatorEngine::decodeEvent(e, &eventType, &button);
// Constrain angle if action checked XOR shift button pressed.
modifiers.constrainRatioAndAngle = (bool(constrainRatioAndAngleActive()) != bool(e->modifiers() & Qt::ShiftModifier));
const QPointF globalPosF = e->globalPosF();
const QPointF localPosF = globalPosF - localOriginInGlobal;
......@@ -1222,6 +1229,16 @@ void PageViewAnnotator::setContinuousMode(bool enabled)
Okular::Settings::self()->save();
}
bool PageViewAnnotator::constrainRatioAndAngleActive()
{
return m_constrainRatioAndAngle;
}
void PageViewAnnotator::setConstrainRatioAndAngle(bool enabled)
{
m_constrainRatioAndAngle = enabled;
}
void PageViewAnnotator::setToolsEnabled(bool enabled)
{
if (m_actionHandler)
......
......@@ -92,6 +92,11 @@ public:
void setupActionsPostGUIActivated();
// @return Is continuous mode active (pin annotation)?
bool continuousMode();
/**
* State of constrain ratio and angle action.
* While annotating, this value is XOR-ed with the Shift modifier.
*/
bool constrainRatioAndAngleActive();
// enable/disable the annotation actions
void setToolsEnabled(bool enabled);
// enable/disable the text-selection annotation actions
......@@ -120,6 +125,11 @@ public:
public Q_SLOTS:
void setContinuousMode(bool enabled);
/**
* State of constrain ratio and angle action.
* While annotating, this value is XOR-ed with the Shift modifier.
*/
void setConstrainRatioAndAngle(bool enabled);
void addToQuickAnnotations();
void slotAdvancedSettings();
......@@ -142,6 +152,7 @@ private:
AnnotationTools *m_toolsDefinition;
AnnotationTools *m_quickToolsDefinition;
bool m_continuousMode;
bool m_constrainRatioAndAngle;
// creation related variables
int m_lastToolID;
......
......@@ -1237,7 +1237,7 @@ QRect PresentationWidget::routeMouseDrawingEvent(QMouseEvent *e)
AnnotatorEngine::Modifiers modifiers;
// figure out the event type and button
AnnotatorEngine::decodeEvent(e, &eventType, &button, &modifiers);
AnnotatorEngine::decodeEvent(e, &eventType, &button);
static bool hasclicked = false;
if (eventType == AnnotatorEngine::Press)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment