diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -346,6 +346,7 @@ part.cpp extensions.cpp ui/embeddedfilesdialog.cpp + ui/annotationactionhandler.cpp ui/annotwindow.cpp ui/annotationmodel.cpp ui/annotationpopup.cpp diff --git a/part.rc b/part.rc --- a/part.rc +++ b/part.rc @@ -1,5 +1,5 @@ - + &File @@ -106,4 +106,23 @@ +Annotations toolbar + + + + + + + + + + + + + + + + + + diff --git a/ui/annotationactionhandler.h b/ui/annotationactionhandler.h new file mode 100644 --- /dev/null +++ b/ui/annotationactionhandler.h @@ -0,0 +1,63 @@ +/************************************************************************** +* Copyright (C) 2019 by Simone Gaiarin * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +**************************************************************************/ + +#ifndef _ANNOTATIONACTIONHANDLER_H_ +#define _ANNOTATIONACTIONHANDLER_H_ + +#include + +class QAction; +class QColor; +class QFont; +class KActionCollection; +class PageView; +class AnnotationActionHandlerPrivate; + +/** + * @short Handles all the actions of the annotation tools toolbar + * + */ +class AnnotationActionHandler : public QObject +{ + Q_OBJECT + + public: + AnnotationActionHandler( PageView * parent ); + ~AnnotationActionHandler(); + + void setupActions( KActionCollection *ac ); + + void deselectAllAnnotationActions(); + + void setToolsEnabled( bool on ); + void setTextToolsEnabled( bool on ); + + Q_SIGNALS: + // the tool 'toolID' has been selected + void toolSelected( int toolID ); + // the button to enable continuous mode has been toggled + void pinAnnotationToolToggled( bool enabled ); + void colorChanged( QColor color ); + void innerColorChanged( QColor color ); + void fontChanged( QFont font ); + void widthChanged( double width ); + + private: + friend class AnnotationActionHandlerPrivate; + class AnnotationActionHandlerPrivate * d; + + private Q_SLOTS: + void slotToolSelected( int toolID ); + void slotSelectBorderColor(); + void slotSelectInnerColor(); + void slotSelectAnnotationFont(); + void slotSelectAnnotationWidth( int width ); +}; + +#endif // _ANNOTATIONACTIONHANDLER_H_ diff --git a/ui/annotationactionhandler.cpp b/ui/annotationactionhandler.cpp new file mode 100644 --- /dev/null +++ b/ui/annotationactionhandler.cpp @@ -0,0 +1,398 @@ +/************************************************************************** +* Copyright (C) 2019 by Simone Gaiarin * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +**************************************************************************/ + +#include "annotationactionhandler.h" + +// qt includes +#include +#include +#include +#include + +// kde includes +#include +#include + +// local includes +#include "pageview.h" +#include "toolaction.h" +#include "core/form.h" +#include "settings.h" + +class AnnotationActionHandlerPrivate +{ +public: + AnnotationActionHandlerPrivate( AnnotationActionHandler * qq ) + : q( qq ), m_currentBorderColor( QColor("yellow") ), + m_currentInnerColor( QColor("#00000000") ), m_currentFont( QFont() ) + { + } + + QIcon colorizeIcon(QIcon &icon, const QColor &color); + void setBorderColorActionIcon( QColor color ); + void setInnerColorActionIcon( QColor color ); + void enableConfigActionsForAnnotation( QString annotType ); + + AnnotationActionHandler * q; + + QList * m_annotationTools; + QList * m_textAnnotationTools; + QActionGroup * m_annotationToolsGroup; + QActionGroup * m_widthActionGroup; + + QAction * m_borderColorAction; + QAction * m_innerColorAction; + QAction * m_fontAction; + ToolAction * m_widthAction; + + QColor m_currentBorderColor; + QColor m_currentInnerColor; + QFont m_currentFont; +}; + +QIcon AnnotationActionHandlerPrivate::colorizeIcon(QIcon &icon, const QColor &color) +{ + //FIXME: Use GuiUtils::colorize if possible instead or write a decent version of this method + QPixmap iconPixmap = icon.pixmap(32, 32); + QBitmap mask = iconPixmap.createMaskFromColor(QColor(Qt::transparent), Qt::MaskInColor); + iconPixmap.fill(color); + iconPixmap.setMask(mask); + return QIcon(iconPixmap); +} + +void AnnotationActionHandlerPrivate::setBorderColorActionIcon( QColor color ) +{ + // Cannot use the current icon of m_borderColorAction to define the mask to avoid trubles + // the alpha channel is zero + QIcon icon = QIcon::fromTheme( QStringLiteral("color-picker") ); + QIcon colorizedColorPicker = colorizeIcon( icon, color ); + m_borderColorAction->setIcon( colorizedColorPicker ); +} + +void AnnotationActionHandlerPrivate::setInnerColorActionIcon( QColor color ) +{ + // Cannot use the current icon of m_borderColorAction to define the mask to avoid trubles + // the alpha channel is zero + QIcon icon = QIcon::fromTheme( QStringLiteral("color-picker") ); + QIcon colorizedColorPicker = colorizeIcon( icon, color ); + m_innerColorAction->setIcon( colorizedColorPicker ); +} + +void AnnotationActionHandlerPrivate::enableConfigActionsForAnnotation( QString annotType = "none" ) +{ + if( annotType == QStringLiteral( "note-inline" ) || annotType == QStringLiteral( "typewriter" ) ) { + m_fontAction->setEnabled( true ); + } else { + m_fontAction->setEnabled( false ); + } + if( annotType == QStringLiteral( "stamp" ) || annotType == QStringLiteral( "none" ) ) { + m_borderColorAction->setEnabled( false ); + } else { + m_borderColorAction->setEnabled( true ); + } + if( annotType == QStringLiteral( "rectangle" ) || annotType == QStringLiteral( "ellipse" ) + || annotType == QStringLiteral( "polygon" ) || annotType == QStringLiteral( "note-inline" ) ) { + m_innerColorAction->setEnabled( true ); + } else { + m_innerColorAction->setEnabled( false ); + } + if( annotType == QStringLiteral( "ink" ) || + annotType == QStringLiteral( "straight-line" ) || annotType == QStringLiteral( "rectangle" ) + || annotType == QStringLiteral( "ellipse" ) || annotType == QStringLiteral( "polygon" ) ) + { + m_widthAction->setEnabled( true ); + m_widthActionGroup->setEnabled( true ); // FIXME: Remove this action group + } else { + m_widthAction->setEnabled( false ); + m_widthActionGroup->setEnabled( false ); + } +} + +AnnotationActionHandler::AnnotationActionHandler( PageView * parent) + : QObject( parent ), d( new AnnotationActionHandlerPrivate( this ) ) +{ +} + +AnnotationActionHandler::~AnnotationActionHandler() +{ + // delete the private data storage structure + delete d; +} + +void AnnotationActionHandler::setupActions( KActionCollection * ac ) +{ + // Text markup + QAction * annHighlighter = new QAction(QIcon::fromTheme( QStringLiteral("draw-eraser") ), "Highlighter", this); + annHighlighter->setCheckable( true ); + ac->addAction(QStringLiteral("annotation_highlighter"), annHighlighter ); + + QAction * annUnderline = new QAction(QIcon::fromTheme( QStringLiteral("format-text-underline") ), "Underline", this); + annUnderline->setCheckable( true ); + ac->addAction(QStringLiteral("annotation_underline"), annUnderline ); + + QAction * annSquiggle = new QAction(QIcon::fromTheme( QStringLiteral("format-text-underline") ), "Squiggle", this); + annSquiggle->setCheckable( true ); + ac->addAction(QStringLiteral("annotation_squiggle"), annSquiggle ); + + QAction * annStrikeout= new QAction(QIcon::fromTheme( QStringLiteral("format-text-strikethrough") ), "Strike out", this); + annStrikeout->setCheckable( true ); + ac->addAction(QStringLiteral("annotation_strike_out"), annStrikeout ); + + // Notes + QAction * annTypewriter = new QAction(QIcon::fromTheme( QStringLiteral("text-convert-to-regular") ), "Typewriter", this); + annTypewriter->setCheckable( true ); + ac->addAction(QStringLiteral("annotation_typewriter"), annTypewriter ); + + QAction * annInlineNote = new QAction(QIcon::fromTheme( QStringLiteral("note") ), "Inline note", this); + annInlineNote->setCheckable( true ); + ac->addAction(QStringLiteral("annotation_inline_note"), annInlineNote ); + + QAction * annPopupNote = new QAction(QIcon::fromTheme( QStringLiteral("edit-comment") ), "Popup note", this); + annPopupNote->setCheckable( true ); + ac->addAction(QStringLiteral("annotation_popup_note"), annPopupNote ); + + QAction * annFreehandLine = new QAction(QIcon::fromTheme( QStringLiteral("draw-freehand") ), "Straight line", this); + annFreehandLine->setCheckable( true ); + ac->addAction(QStringLiteral("annotation_freehand_line"), annFreehandLine ); + + // Geometrical shapes + QAction * annStraightLine = new QAction(QIcon::fromTheme( QStringLiteral("draw-line") ), "Straight line", this); + annStraightLine->setCheckable( true ); + + QAction * annArrow = new QAction(QIcon::fromTheme( QStringLiteral("circular-arrow-shape") ), "Arrow", this); + annArrow->setCheckable( true ); + + QAction * annRectangle = new QAction(QIcon::fromTheme( QStringLiteral("draw-rectangle") ), "Rectangle", this); + annRectangle->setCheckable( true ); + + QAction * annEllipse = new QAction(QIcon::fromTheme( QStringLiteral("draw-ellipse") ), "Ellipse", this); + annEllipse->setCheckable( true ); + + QAction * annPolygon = new QAction(QIcon::fromTheme( QStringLiteral("draw-polyline") ), "Polygon", this); + annPolygon->setCheckable( true ); + + ToolAction *ta = new ToolAction( this ); + ac->addAction( QStringLiteral("annotation_geometrical_shape"), ta ); + ta->addAction( annStraightLine ); + ta->addAction( annArrow ); + ta->addAction( annRectangle ); + ta->addAction( annEllipse ); + ta->addAction( annPolygon ); + + // Settings + d->m_widthActionGroup = new QActionGroup(this); + d->m_widthActionGroup->setExclusive( true ); //FIXME: Use ta.selectableActionGroup instead + d->m_widthActionGroup->setEnabled( false ); + d->m_widthAction = new ToolAction( this ); + d->m_widthAction->setEnabled( false ); + ac->addAction( QStringLiteral("annotation_size"), d->m_widthAction ); + QSignalMapper * widthSelectorSignalMapper = new QSignalMapper(this); + for( int i = 1; i <= 10; i++ ) + { + QAction * ann = new QAction(QIcon::fromTheme( QStringLiteral("newline") ), QString("Width %1").arg(i/2.0), this); + ann->setCheckable( true ); + d->m_widthAction->addAction( ann ); + d->m_widthActionGroup->addAction( ann ); + connect(ann, SIGNAL(triggered()), widthSelectorSignalMapper, SLOT(map())); + widthSelectorSignalMapper->setMapping(ann, i); + } + d->m_widthActionGroup->actions()[0]->setChecked( true ); + + d->m_borderColorAction = new QAction( QIcon(), "Pick color", this); + d->m_borderColorAction->setEnabled( false ); + d->setBorderColorActionIcon( QColor( "black" ) ); + ac->addAction(QStringLiteral("annotation_border_color"), d->m_borderColorAction ); + + d->m_innerColorAction = new QAction( QIcon(), "Pick inner color", this); + d->m_innerColorAction->setEnabled( false ); + d->setInnerColorActionIcon( QColor( "black" ) ); + ac->addAction(QStringLiteral("annotation_inner_color"), d->m_innerColorAction ); + + d->m_fontAction = new QAction( QIcon::fromTheme( QStringLiteral("font-face") ), "Choose font", this ); + d->m_fontAction->setEnabled( false ); + ac->addAction(QStringLiteral("annotation_font"), d->m_fontAction ); + + QAction * pinAnnotationTool = new QAction(QIcon::fromTheme( QStringLiteral("port") ), "Pin annotation", this); + pinAnnotationTool->setCheckable( true ); + pinAnnotationTool->setChecked( true ); + ac->addAction(QStringLiteral("pin_annotation_tool"), pinAnnotationTool ); + + // The order in which the actions are added is relevant to connect + // them to the correct tool id. See for loop below. + d->m_annotationToolsGroup = new QActionGroup(this); + d->m_annotationToolsGroup->addAction(annHighlighter); + d->m_annotationToolsGroup->addAction(annUnderline); + d->m_annotationToolsGroup->addAction(annSquiggle); + d->m_annotationToolsGroup->addAction(annStrikeout); + d->m_annotationToolsGroup->addAction(annTypewriter); + d->m_annotationToolsGroup->addAction(annInlineNote); + d->m_annotationToolsGroup->addAction(annPopupNote); + d->m_annotationToolsGroup->addAction(annFreehandLine); + d->m_annotationToolsGroup->addAction(annStraightLine); + d->m_annotationToolsGroup->addAction(annArrow); + d->m_annotationToolsGroup->addAction(annRectangle); + d->m_annotationToolsGroup->addAction(annEllipse); + d->m_annotationToolsGroup->addAction(annPolygon); + + d->m_annotationTools = new QList(d->m_annotationToolsGroup->actions()); + d->m_annotationTools->append(pinAnnotationTool); + + d->m_textAnnotationTools = new QList(); + d->m_textAnnotationTools->append(annHighlighter); + d->m_textAnnotationTools->append(annUnderline); + d->m_textAnnotationTools->append(annSquiggle); + d->m_textAnnotationTools->append(annStrikeout); + + QSignalMapper * annSignalMapper = new QSignalMapper(this); + int i = 1; + foreach( QAction * ann, d->m_annotationToolsGroup->actions() ) + { + connect(ann, SIGNAL(triggered()), annSignalMapper, SLOT(map())); + annSignalMapper->setMapping(ann, i++); + } + connect(annSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotToolSelected(int))); + + connect(widthSelectorSignalMapper, SIGNAL(mapped(int)), this, SLOT(slotSelectAnnotationWidth(int))); + connect(d->m_borderColorAction, SIGNAL(triggered()), this, SLOT(slotSelectBorderColor())); + connect(d->m_innerColorAction, SIGNAL(triggered()), this, SLOT(slotSelectInnerColor())); + connect(d->m_fontAction, SIGNAL(triggered()), this, SLOT(slotSelectAnnotationFont())); + connect(pinAnnotationTool, SIGNAL(toggled(bool)), this, SIGNAL(pinAnnotationToolToggled(bool))); +} + +void AnnotationActionHandler::deselectAllAnnotationActions() +{ + QAction * currentAction = d->m_annotationToolsGroup->checkedAction(); + currentAction->setChecked( false ); + + d->enableConfigActionsForAnnotation(); + + emit toolSelected( -1 ); +} + +void AnnotationActionHandler::setToolsEnabled( bool on ) +{ + foreach( QAction * ann, *d->m_annotationTools ) + { + ann->setEnabled( on ); + } +} + +void AnnotationActionHandler::setTextToolsEnabled( bool on ) +{ + foreach( QAction * ann, *d->m_textAnnotationTools ) + { + ann->setEnabled( on ); + } +} + +void AnnotationActionHandler::slotToolSelected(int toolID) +{ + const QStringList annotationTools = Okular::Settings::annotationTools(); + + QDomDocument doc; + doc.setContent( annotationTools.at( toolID - 1 ) ); + + QDomElement toolElement = doc.documentElement(); + QDomElement engineElement = toolElement.elementsByTagName( QStringLiteral("engine") ).item( 0 ).toElement(); + QDomElement annElement = engineElement.elementsByTagName( QStringLiteral("annotation") ).item( 0 ).toElement(); + const QString annotType = toolElement.attribute( QStringLiteral("type") ); + + if( annElement.hasAttribute( QStringLiteral( "color" ) ) ) + { + if (annotType == "note-inline" || annotType == "typewriter" ) { + d->m_currentInnerColor = QColor( annElement.attribute( QStringLiteral( "color" ) ) ); + d->setInnerColorActionIcon( d->m_currentInnerColor ); + } else { + d->m_currentBorderColor = QColor( annElement.attribute( QStringLiteral( "color" ) ) ); + d->setBorderColorActionIcon( d->m_currentBorderColor ); + } + } + if( annElement.hasAttribute( QStringLiteral( "innerColor" ) ) ) { + d->m_currentInnerColor = QColor( annElement.attribute( QStringLiteral( "innerColor" ) ) ); + } else { + d->m_currentInnerColor = QColor( "00000000" ); + d->m_currentInnerColor.setAlpha( 0 ); + } + d->setInnerColorActionIcon( d->m_currentInnerColor ); + if( annElement.hasAttribute( QStringLiteral( "textColor" ) ) ) { + d->m_currentBorderColor = QColor( annElement.attribute( QStringLiteral( "textColor" ) ) ); + d->setBorderColorActionIcon( d->m_currentBorderColor ); + } + if( annElement.hasAttribute( QStringLiteral( "font" ) ) ) + { + d->m_currentFont.fromString( annElement.attribute( QStringLiteral( "font" ) ) ); + } + if( annElement.hasAttribute( QStringLiteral( "width" ) ) ) + { + double width = annElement.attribute( QStringLiteral( "width" ) ).toDouble(); + int widthNumber = int( 2*width ); + // FIXME: Add some checks here + if ( widthNumber > 0 ) { + d->m_widthActionGroup->actions()[widthNumber-1]->setChecked( true ); + } + } + + d->enableConfigActionsForAnnotation( annotType ); + + emit toolSelected( toolID ); +} + +void AnnotationActionHandler::slotSelectBorderColor() +{ + QColor selectedColor = QColorDialog::getColor(d->m_currentBorderColor, nullptr, i18n("Select annotation color"), QColorDialog::ShowAlphaChannel); + if (!selectedColor.isValid()) + return; + + d->m_currentBorderColor = selectedColor; + + d->setBorderColorActionIcon( d->m_currentBorderColor ); + + if ( d->m_currentInnerColor.alpha() != selectedColor.alpha() && d->m_currentInnerColor.alpha() > 0 ) { + d->m_currentInnerColor.setAlpha( selectedColor.alpha() ); + d->setInnerColorActionIcon( d->m_currentInnerColor ); + } + + emit colorChanged( d->m_currentBorderColor ); +} + +void AnnotationActionHandler::slotSelectInnerColor() +{ + QColor selectedColor = QColorDialog::getColor(d->m_currentInnerColor, nullptr, i18n("Select annotation color"), QColorDialog::ShowAlphaChannel); + if (!selectedColor.isValid()) + return; + + d->m_currentInnerColor = selectedColor; + + d->setInnerColorActionIcon( d->m_currentInnerColor ); + + emit innerColorChanged( d->m_currentInnerColor ); + + if ( selectedColor.alpha() > 0 && d->m_currentBorderColor.alpha() != selectedColor.alpha() ) { + d->m_currentBorderColor.setAlpha( selectedColor.alpha() ); + d->setBorderColorActionIcon( d->m_currentBorderColor ); + emit colorChanged( d->m_currentBorderColor ); + } +} + +void AnnotationActionHandler::slotSelectAnnotationFont() +{ + bool ok; + QFont selectedFont = QFontDialog::getFont(&ok, d->m_currentFont); + if (ok) { + d->m_currentFont = selectedFont; + emit fontChanged( d->m_currentFont ); + } +} + +void AnnotationActionHandler::slotSelectAnnotationWidth( int widthNumber ) +{ + emit widthChanged( widthNumber / 2.0 ); +} + +#include "moc_annotationactionhandler.cpp" diff --git a/ui/data/tools.xml b/ui/data/tools.xml --- a/ui/data/tools.xml +++ b/ui/data/tools.xml @@ -17,63 +17,84 @@ Geom --> - - - + + + 1 - - - + + + 2 - - - + + + 3 - - - + + + 4 - - - + + + + + + + + 5 - - - + + + 6 - - - + + + 7 - - - - + + + + - 8 - - - + + + - 9 - - - + + + + + + + + + + + + + + + + + + 8 + diff --git a/ui/pageview.cpp b/ui/pageview.cpp --- a/ui/pageview.cpp +++ b/ui/pageview.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -465,6 +466,7 @@ qDeleteAll( d->items ); delete d->formsWidgetController; d->document->removeObserver( this ); + d->annotator->saveAnnotationTools(); delete d; } @@ -660,9 +662,9 @@ d->aMouseMagnifier->setActionGroup( d->mouseModeActionGroup ); d->aMouseMagnifier->setChecked( Okular::Settings::mouseMode() == Okular::Settings::EnumMouseMode::Magnifier ); - d->aToggleAnnotator = new KToggleAction(QIcon::fromTheme( QStringLiteral("draw-freehand") ), i18n("&Review"), this); + d->aToggleAnnotator = new KToggleToolBarAction( "annotationToolBar", i18n("&Review"), this); //FIXME: Not working + d->aToggleAnnotator->setIcon( QIcon::fromTheme( QStringLiteral("draw-freehand") ) ); ac->addAction(QStringLiteral("mouse_toggle_annotate"), d->aToggleAnnotator ); - d->aToggleAnnotator->setCheckable( true ); connect( d->aToggleAnnotator, &QAction::toggled, this, &PageView::slotToggleAnnotator ); ac->setDefaultShortcut(d->aToggleAnnotator, Qt::Key_F6); @@ -732,6 +734,11 @@ connect(d->document, &Okular::Document::canRedoChanged, kredo, &QAction::setEnabled); kundo->setEnabled(false); kredo->setEnabled(false); + + slotToggleAnnotator( true ); // TODO: The code in slotToggleAnnotator should be moved + // somewhere else. We need to switch to normal mode each time an + // annotation is selected + d->annotator->setupActions( ac ); } bool PageView::canFitPageWidth() const @@ -5021,9 +5028,6 @@ Okular::Settings::setMouseMode( d->mouseMode ); // hide the messageWindow d->messageWindow->hide(); - // reshow the annotator toolbar if hiding was forced (and if it is not already visible) - if ( d->annotator && d->annotator->hidingWasForced() && d->aToggleAnnotator && !d->aToggleAnnotator->isChecked() ) - d->aToggleAnnotator->trigger(); // force an update of the cursor updateCursor(); Okular::Settings::self()->save(); @@ -5035,12 +5039,6 @@ Okular::Settings::setMouseMode( d->mouseMode ); // change the text in messageWindow (and show it if hidden) d->messageWindow->display( i18n( "Select zooming area. Right-click to zoom out." ), QString(), PageViewMessage::Info, -1 ); - // force hiding of annotator toolbar - if ( d->aToggleAnnotator && d->aToggleAnnotator->isChecked() ) - { - d->aToggleAnnotator->trigger(); - d->annotator->setHidingForced( true ); - } // force an update of the cursor updateCursor(); Okular::Settings::self()->save(); @@ -5063,12 +5061,6 @@ Okular::Settings::setMouseMode( d->mouseMode ); // change the text in messageWindow (and show it if hidden) d->messageWindow->display( i18n( "Draw a rectangle around the text/graphics to copy." ), QString(), PageViewMessage::Info, -1 ); - // force hiding of annotator toolbar - if ( d->aToggleAnnotator && d->aToggleAnnotator->isChecked() ) - { - d->aToggleAnnotator->trigger(); - d->annotator->setHidingForced( true ); - } // force an update of the cursor updateCursor(); Okular::Settings::self()->save(); @@ -5080,12 +5072,6 @@ Okular::Settings::setMouseMode( d->mouseMode ); // change the text in messageWindow (and show it if hidden) d->messageWindow->display( i18n( "Select text" ), QString(), PageViewMessage::Info, -1 ); - // force hiding of annotator toolbar - if ( d->aToggleAnnotator && d->aToggleAnnotator->isChecked() ) - { - d->aToggleAnnotator->trigger(); - d->annotator->setHidingForced( true ); - } // force an update of the cursor updateCursor(); Okular::Settings::self()->save(); @@ -5099,12 +5085,6 @@ d->messageWindow->display( i18n( "Draw a rectangle around the table, then click near edges to divide up; press Esc to clear." ), QString(), PageViewMessage::Info, -1 ); - // force hiding of annotator toolbar - if ( d->aToggleAnnotator && d->aToggleAnnotator->isChecked() ) - { - d->aToggleAnnotator->trigger(); - d->annotator->setHidingForced( true ); - } // force an update of the cursor updateCursor(); Okular::Settings::self()->save(); @@ -5163,7 +5143,6 @@ // initialize/reset annotator (and show/hide toolbar) d->annotator->setEnabled( on ); - d->annotator->setHidingForced( false ); inHere = false; } @@ -5307,12 +5286,6 @@ d->mouseMode = Okular::Settings::EnumMouseMode::TrimSelect; // change the text in messageWindow (and show it if hidden) d->messageWindow->display( i18n( "Draw a rectangle around the page area you wish to keep visible" ), QString(), PageViewMessage::Info, -1 ); - // force hiding of annotator toolbar - if ( d->aToggleAnnotator && d->aToggleAnnotator->isChecked() ) - { - d->aToggleAnnotator->trigger(); - d->annotator->setHidingForced( true ); - } // force an update of the cursor updateCursor(); } else { diff --git a/ui/pageviewannotator.h b/ui/pageviewannotator.h --- a/ui/pageviewannotator.h +++ b/ui/pageviewannotator.h @@ -10,16 +10,20 @@ #ifndef _OKULAR_PAGEVIEWANNOTATOR_H_ #define _OKULAR_PAGEVIEWANNOTATOR_H_ +#include #include #include #include +#include + #include "pageviewutils.h" #include "annotationtools.h" class QKeyEvent; class QMouseEvent; class QPainter; +class AnnotationActionHandler; namespace Okular { @@ -54,17 +58,16 @@ PageViewAnnotator( PageView * parent, Okular::Document * storage ); ~PageViewAnnotator(); + void setupActions( KActionCollection *ac ); + // called to show/hide the editing toolbar void setEnabled( bool enabled ); // called to toggle the usage of text annotating tools void setTextToolsEnabled( bool enabled ); void setToolsEnabled( bool enabled ); - void setHidingForced( bool forced ); - bool hidingWasForced() const; - // methods used when creating the annotation // @return Is a tool currently selected? bool active() const; @@ -88,18 +91,26 @@ static QString defaultToolName( const QDomElement &toolElement ); static QPixmap makeToolPixmap( const QDomElement &toolElement ); + void saveAnnotationTools(); + private Q_SLOTS: void slotToolSelected( int toolID ); + void slotAnnotationColorChanged( QColor color ); + void slotAnnotationInnerColorChanged( QColor color ); + void slotAnnotationFontChanged( QFont font ); + void slotAnnotationWidthChanged( double width ); void slotSaveToolbarOrientation( int side ); - void slotToolDoubleClicked( int toolID ); + void slotPinAnnotationToolToggled( bool enabled ); private: void detachAnnotation(); + QDomElement currentEngineElement(); + QDomElement currentAnnotationElement(); // global class pointers Okular::Document * m_document; PageView * m_pageView; - PageViewToolBar * m_toolBar; + AnnotationActionHandler * m_toolBar; AnnotatorEngine * m_engine; QDomElement m_toolsDefinition; QLinkedList m_items; diff --git a/ui/pageviewannotator.cpp b/ui/pageviewannotator.cpp --- a/ui/pageviewannotator.cpp +++ b/ui/pageviewannotator.cpp @@ -37,6 +37,7 @@ #include "core/document.h" #include "core/page.h" #include "core/annotations.h" +#include "ui/annotationactionhandler.h" #include "settings.h" #include "annotationtools.h" #include "guiutils.h" @@ -162,10 +163,7 @@ // set font color if ( m_annotElement.hasAttribute( QStringLiteral("textColor") ) ) { - if ( inplaceIntent == Okular::TextAnnotation::TypeWriter ) - ta->setTextColor( m_annotElement.attribute( QStringLiteral("textColor") ) ); - else - ta->setTextColor( Qt::black ); + ta->setTextColor( m_annotElement.attribute( QStringLiteral("textColor") ) ); } //set width if ( m_annotElement.hasAttribute( QStringLiteral ( "width" ) ) ) @@ -660,14 +658,14 @@ PageViewAnnotator::PageViewAnnotator( PageView * parent, Okular::Document * storage ) : QObject( parent ), m_document( storage ), m_pageView( parent ), m_toolBar( nullptr ), m_engine( nullptr ), m_textToolsEnabled( false ), m_toolsEnabled( false ), - m_continuousMode( false ), m_hidingWasForced( false ), m_lastToolID( -1 ), m_lockedItem( nullptr ) + m_continuousMode( true ), m_hidingWasForced( false ), m_lastToolID( -1 ), m_lockedItem( nullptr ) { reparseConfig(); } void PageViewAnnotator::reparseConfig() { - m_items.clear(); + //m_items.clear(); // Read tool list from configuration. It's a list of XML elements const QStringList userTools = Okular::Settings::annotationTools(); @@ -685,33 +683,33 @@ } // Create the AnnotationToolItems from the XML dom tree - QDomNode toolDescription = m_toolsDefinition.firstChild(); - while ( toolDescription.isElement() ) - { - QDomElement toolElement = toolDescription.toElement(); - if ( toolElement.tagName() == QLatin1String("tool") ) - { - AnnotationToolItem item; - item.id = toolElement.attribute(QStringLiteral("id")).toInt(); - if ( toolElement.hasAttribute( QStringLiteral("name") ) ) - item.text = toolElement.attribute( QStringLiteral("name") ); - else - item.text = defaultToolName( toolElement ); - item.pixmap = makeToolPixmap( toolElement ); - QDomNode shortcutNode = toolElement.elementsByTagName( QStringLiteral("shortcut") ).item( 0 ); - if ( shortcutNode.isElement() ) - item.shortcut = shortcutNode.toElement().text(); - QDomNodeList engineNodeList = toolElement.elementsByTagName( QStringLiteral("engine") ); - if ( engineNodeList.size() > 0 ) - { - QDomElement engineEl = engineNodeList.item( 0 ).toElement(); - if ( !engineEl.isNull() && engineEl.hasAttribute( QStringLiteral("type") ) ) - item.isText = engineEl.attribute( QStringLiteral("type") ) == QLatin1String( "TextSelector" ); - } - m_items.push_back( item ); - } - toolDescription = toolDescription.nextSibling(); - } +// QDomNode toolDescription = m_toolsDefinition.firstChild(); +// while ( toolDescription.isElement() ) +// { +// QDomElement toolElement = toolDescription.toElement(); +// if ( toolElement.tagName() == QLatin1String("tool") ) +// { +// AnnotationToolItem item; +// item.id = toolElement.attribute(QStringLiteral("id")).toInt(); +// if ( toolElement.hasAttribute( QStringLiteral("name") ) ) +// item.text = toolElement.attribute( QStringLiteral("name") ); +// else +// item.text = defaultToolName( toolElement ); +// item.pixmap = makeToolPixmap( toolElement ); +// QDomNode shortcutNode = toolElement.elementsByTagName( QStringLiteral("shortcut") ).item( 0 ); +// if ( shortcutNode.isElement() ) +// item.shortcut = shortcutNode.toElement().text(); +// QDomNodeList engineNodeList = toolElement.elementsByTagName( QStringLiteral("engine") ); +// if ( engineNodeList.size() > 0 ) +// { +// QDomElement engineEl = engineNodeList.item( 0 ).toElement(); +// if ( !engineEl.isNull() && engineEl.hasAttribute( QStringLiteral("type") ) ) +// item.isText = engineEl.attribute( QStringLiteral("type") ) == QLatin1String( "TextSelector" ); +// } +// m_items.push_back( item ); +// } +// toolDescription = toolDescription.nextSibling(); +// } } PageViewAnnotator::~PageViewAnnotator() @@ -723,65 +721,44 @@ { if ( !on ) { - // remove toolBar - if ( m_toolBar ) - m_toolBar->hideAndDestroy(); - m_toolBar = nullptr; // deactivate the active tool, if any slotToolSelected( -1 ); return; } - // if no tools are defined, don't show the toolbar - if ( !m_toolsDefinition.hasChildNodes() ) - return; - // create toolBar if ( !m_toolBar ) { - m_toolBar = new PageViewToolBar( m_pageView, m_pageView->viewport() ); - m_toolBar->setSide( (PageViewToolBar::Side)Okular::Settings::editToolBarPlacement() ); - m_toolBar->setItems( m_items ); - m_toolBar->setToolsEnabled( m_toolsEnabled ); - m_toolBar->setTextToolsEnabled( m_textToolsEnabled ); - connect(m_toolBar, &PageViewToolBar::toolSelected, this, &PageViewAnnotator::slotToolSelected); - connect(m_toolBar, &PageViewToolBar::orientationChanged, this, &PageViewAnnotator::slotSaveToolbarOrientation); - - connect(m_toolBar, &PageViewToolBar::buttonDoubleClicked, this, &PageViewAnnotator::slotToolDoubleClicked); - m_toolBar->setCursor(Qt::ArrowCursor); + m_toolBar = new AnnotationActionHandler( m_pageView ); + connect(m_toolBar, &AnnotationActionHandler::toolSelected, this, &PageViewAnnotator::slotToolSelected); + connect(m_toolBar, &AnnotationActionHandler::widthChanged, this, &PageViewAnnotator::slotAnnotationWidthChanged); + connect(m_toolBar, &AnnotationActionHandler::colorChanged, this, &PageViewAnnotator::slotAnnotationColorChanged); + connect(m_toolBar, &AnnotationActionHandler::innerColorChanged, this, &PageViewAnnotator::slotAnnotationInnerColorChanged); + connect(m_toolBar, &AnnotationActionHandler::fontChanged, this, &PageViewAnnotator::slotAnnotationFontChanged); + connect(m_toolBar, &AnnotationActionHandler::pinAnnotationToolToggled, this, &PageViewAnnotator::slotPinAnnotationToolToggled); } - - // show the toolBar - m_toolBar->showAndAnimate(); } void PageViewAnnotator::setTextToolsEnabled( bool enabled ) { + //FIXME: Add code to enable tools m_textToolsEnabled = enabled; if ( m_toolBar ) m_toolBar->setTextToolsEnabled( m_textToolsEnabled ); } void PageViewAnnotator::setToolsEnabled( bool enabled ) { + //FIXME: Add code to enable tools m_toolsEnabled = enabled; if ( m_toolBar ) m_toolBar->setToolsEnabled( m_toolsEnabled ); } -void PageViewAnnotator::setHidingForced( bool forced ) -{ - m_hidingWasForced = forced; -} - -bool PageViewAnnotator::hidingWasForced() const -{ - return m_hidingWasForced; -} - bool PageViewAnnotator::active() const { - return m_engine && m_toolBar; + //FIXME: + return m_engine;// && m_toolBar; } bool PageViewAnnotator::annotating() const @@ -893,18 +870,6 @@ return QRect(); } - // We set all tablet events that take place over the annotations toolbar to ignore so that corresponding mouse - // events will be delivered to the toolbar. However, we still allow the annotations code to handle - // TabletMove and TabletRelease events in case the user is drawing an annotation onto the toolbar. - const QPoint toolBarPos = m_toolBar->mapFromGlobal( e->globalPos() ); - const QRect toolBarRect = m_toolBar->rect(); - if ( toolBarRect.contains( toolBarPos ) ) - { - e->ignore(); - if (e->type() == QEvent::TabletPress) - return QRect(); - } - AnnotatorEngine::EventType eventType; AnnotatorEngine::Button button; @@ -928,7 +893,8 @@ bool PageViewAnnotator::routePaints( const QRect & wantedRect ) const { - return m_engine && m_toolBar && wantedRect.intersects( m_lastDrawnRect ) && m_lockedItem; + //FIXME: Add check on annotation toolbar avability + return m_engine && wantedRect.intersects( m_lastDrawnRect ) && m_lockedItem; } void PageViewAnnotator::routePaint( QPainter * painter, const QRect & paintRect ) @@ -972,7 +938,6 @@ m_lastDrawnRect = QRect(); } - if ( toolID != m_lastToolID ) m_continuousMode = false; // store current tool for later usage m_lastToolID = toolID; @@ -1071,14 +1036,94 @@ Okular::Settings::self()->save(); } -void PageViewAnnotator::slotToolDoubleClicked( int /*toolID*/ ) +void PageViewAnnotator::slotPinAnnotationToolToggled( bool enabled ) { - m_continuousMode = true; + m_continuousMode = enabled; +} + +QDomElement PageViewAnnotator::currentEngineElement() +{ + QDomElement toolElement = m_toolsDefinition.firstChildElement(); + while( !toolElement.isNull() && toolElement.attribute("id").toInt() != m_lastToolID) { + toolElement = toolElement.nextSiblingElement(); + } + QDomElement engineElement = toolElement.elementsByTagName( QStringLiteral("engine") ).item( 0 ).toElement();; + return engineElement; +} + +QDomElement PageViewAnnotator::currentAnnotationElement() +{ + QDomElement annotationElement = currentEngineElement().elementsByTagName( QStringLiteral("annotation") ).item( 0 ).toElement(); + return annotationElement; +} + +void PageViewAnnotator::slotAnnotationColorChanged( QColor color ) +{ + currentEngineElement().setAttribute( QStringLiteral( "color" ), color.name(QColor::HexRgb ) ); + QDomElement annotationElement = currentAnnotationElement(); + QString annotType = annotationElement.attribute( QStringLiteral( "type" ) ); + if ( annotType == "Typewriter" || annotType == "FreeText" ) { + annotationElement.setAttribute( QStringLiteral( "textColor" ), color.name(QColor::HexArgb) ); + } else { + annotationElement.setAttribute( QStringLiteral( "color" ), color.name(QColor::HexArgb) ); + } + QString opacity = QString::number(color.alphaF(), 'f' /* format */, 1 /* precision */); + annotationElement.setAttribute( QStringLiteral( "opacity" ), opacity ); + + slotToolSelected( m_lastToolID ); +} + +void PageViewAnnotator::slotAnnotationInnerColorChanged( QColor color ) +{ + QDomElement annotationElement = currentAnnotationElement(); + QString annotType = annotationElement.attribute( QStringLiteral( "type" ) ); + if ( annotType == "FreeText" ) { + annotationElement.setAttribute( QStringLiteral( "color" ), color.name(QColor::HexRgb) ); + } else { + if ( color.alpha() == 0 ) { + currentAnnotationElement().removeAttribute( QStringLiteral( "innerColor" ) ); + } else { + currentAnnotationElement().setAttribute( QStringLiteral( "innerColor" ), color.name(QColor::HexArgb) ); + } + } + slotToolSelected( m_lastToolID ); +} + +void PageViewAnnotator::slotAnnotationFontChanged( QFont font ) +{ + currentAnnotationElement().setAttribute( QStringLiteral( "font" ), font.toString() ); + + slotToolSelected( m_lastToolID ); +} + +void PageViewAnnotator::slotAnnotationWidthChanged( double width) +{ + currentAnnotationElement().setAttribute( QStringLiteral( "width" ), width ); + + slotToolSelected( m_lastToolID ); } void PageViewAnnotator::detachAnnotation() { - m_toolBar->selectButton( -1 ); + m_toolBar->deselectAllAnnotationActions(); +} + +void PageViewAnnotator::saveAnnotationTools() +{ + QStringList tools; + QDomElement toolElement = m_toolsDefinition.firstChildElement(); + QString str; + QTextStream stream(&str); + while( !toolElement.isNull() ) + { + str.clear(); + toolElement.save(stream, -1 /* indent disabled */); + tools << str; + toolElement = toolElement.nextSiblingElement(); + } + + Okular::Settings::setAnnotationTools(tools); + Okular::Settings::self()->save(); } QString PageViewAnnotator::defaultToolName( const QDomElement &toolElement ) @@ -1276,6 +1321,11 @@ return pixmap; } +void PageViewAnnotator::setupActions( KActionCollection * ac ) +{ + m_toolBar->setupActions( ac ); +} + #include "moc_pageviewannotator.cpp" /* kate: replace-tabs on; indent-width 4; */ diff --git a/ui/pageviewutils.h b/ui/pageviewutils.h --- a/ui/pageviewutils.h +++ b/ui/pageviewutils.h @@ -17,13 +17,13 @@ #include #include #include -#include - #include "core/area.h" +class KActionCollection; class QAction; class QLabel; +class QMenu; class QTimer; class FormWidgetIface; class PageView; @@ -144,83 +144,4 @@ bool isText; }; -class ToolBarButton : public QToolButton -{ - Q_OBJECT - public: - static const int iconSize = 32; - static const int buttonSize = 40; - - ToolBarButton( QWidget * parent, const AnnotationToolItem &item ); - int buttonID() const { return m_id; } - bool isText() const { return m_isText; } - - Q_SIGNALS: - void buttonDoubleClicked( int buttonID ); - - protected: - void mouseDoubleClickEvent( QMouseEvent * event ) override; - - private: - int m_id; - bool m_isText; -}; - -/** - * @short A widget containing exclusive buttons, that slides in from a side. - * - * This is a shaped widget that slides in from a side of the 'anchor widget' - * it's attached to. It can be dragged and docked on {left,top,right,bottom} - * sides and contains toggable exclusive buttons. - * When a 'tool' of this 'toolBar' is selected, a signal is emitted. - */ -class PageViewToolBar : public QWidget -{ - Q_OBJECT - public: - PageViewToolBar( PageView * parent, QWidget * anchorWidget ); - ~PageViewToolBar(); - - // animated widget controls - enum Side { Left = 0, Top = 1, Right = 2, Bottom = 3 }; - - void setItems( const QLinkedList &items ); - void setSide( Side side ); - - void showAndAnimate(); - void hideAndDestroy(); - - void selectButton( int id ); - - void setToolsEnabled( bool on ); - void setTextToolsEnabled( bool on ); - - // query properties - - Q_SIGNALS: - // the tool 'toolID' has been selected - void toolSelected( int toolID ); - // orientation has been changed - void orientationChanged( int side ); - // a tool button of this toolbar has been double clicked - void buttonDoubleClicked( int buttonID ); - - protected: - // handle widget events { anchor_resize, paint, animation, drag } - bool eventFilter( QObject * o, QEvent * e ) override; - void paintEvent( QPaintEvent * ) override; - void mousePressEvent( QMouseEvent * e ) override; - void mouseMoveEvent( QMouseEvent * e ) override; - void mouseReleaseEvent( QMouseEvent * e ) override; - - private: - // private variables - friend class ToolBarPrivate; - class ToolBarPrivate * d; - - private Q_SLOTS: - void slotAnimate(); - void slotButtonClicked(); -}; - #endif diff --git a/ui/pageviewutils.cpp b/ui/pageviewutils.cpp --- a/ui/pageviewutils.cpp +++ b/ui/pageviewutils.cpp @@ -14,30 +14,14 @@ // qt/kde includes #include -#include -#include -#include -#include -#include +#include #include -#include -#include #include -#include -#include -#include -#include #include -#include - -// system includes -#include // local includes #include "formwidgets.h" -#include "pageview.h" #include "videowidget.h" -#include "core/movie.h" #include "core/page.h" #include "core/form.h" #include "settings.h" @@ -429,520 +413,4 @@ hide(); } - -/*********************/ -/** PageViewToolBar */ -/*********************/ - -ToolBarButton::ToolBarButton( QWidget * parent, const AnnotationToolItem &item ) - : QToolButton( parent ), m_id( item.id ), m_isText( item.isText ) -{ - setCheckable( true ); - setAutoRaise( true ); - resize( buttonSize, buttonSize ); - setIconSize( QSize( iconSize, iconSize ) ); - setIcon( QIcon( item.pixmap ) ); - // set shortcut if defined - if ( !item.shortcut.isEmpty() ) - setShortcut( QKeySequence( item.shortcut ) ); - else - KAcceleratorManager::setNoAccel( this ); - - // if accel is set display it along name - QString accelString = shortcut().toString( QKeySequence::NativeText ); - if ( !accelString.isEmpty() ) - setToolTip( QStringLiteral("%1 [%2]").arg( item.text, accelString ) ); - else - setToolTip( item.text ); -} - -void ToolBarButton::mouseDoubleClickEvent( QMouseEvent * /*event*/ ) -{ - emit buttonDoubleClicked( buttonID() ); -} - -/* PageViewToolBar */ - -static const int toolBarGridSize = 40; - -class ToolBarPrivate -{ -public: - ToolBarPrivate( PageViewToolBar * qq ) - : q( qq ) - { - } - - // rebuild contents and reposition then widget - void buildToolBar(); - void reposition(); - // compute the visible and hidden positions along current side - QPoint getInnerPoint() const; - QPoint getOuterPoint() const; - void selectButton( ToolBarButton * button ); - - PageViewToolBar * q; - - // anchored widget and side - QWidget * anchorWidget; - PageViewToolBar::Side anchorSide; - - // slide in/out stuff - QTimer * animTimer; - QPoint currentPosition; - QPoint endPosition; - bool hiding; - bool visible; - - // background pixmap and buttons - QPixmap backgroundPixmap; - QLinkedList< ToolBarButton * > buttons; -}; - -PageViewToolBar::PageViewToolBar( PageView * parent, QWidget * anchorWidget ) - : QWidget( parent ), d( new ToolBarPrivate( this ) ) -{ - // initialize values of the private data storage structure - d->anchorWidget = anchorWidget; - d->anchorSide = Left; - d->hiding = false; - d->visible = false; - - // create the animation timer - d->animTimer = new QTimer( this ); - connect( d->animTimer, &QTimer::timeout, this, &PageViewToolBar::slotAnimate ); - - // apply a filter to get notified when anchor changes geometry - d->anchorWidget->installEventFilter( this ); - - setContextMenuPolicy( Qt::ActionsContextMenu ); - addAction( parent->actionCollection()->action( QStringLiteral("options_configure_annotations") ) ); -} - -PageViewToolBar::~PageViewToolBar() -{ - // delete the private data storage structure - delete d; -} - -void PageViewToolBar::setItems( const QLinkedList &items ) -{ - // delete buttons if already present - if ( !d->buttons.isEmpty() ) - { - QLinkedList< ToolBarButton * >::iterator it = d->buttons.begin(), end = d->buttons.end(); - for ( ; it != end; ++it ) - delete *it; - d->buttons.clear(); - } - - // create new buttons for given items - QLinkedList::const_iterator it = items.begin(), end = items.end(); - for ( ; it != end; ++it ) - { - ToolBarButton * button = new ToolBarButton( this, *it ); - connect(button, &ToolBarButton::clicked, this, &PageViewToolBar::slotButtonClicked); - connect(button, &ToolBarButton::buttonDoubleClicked, this, &PageViewToolBar::buttonDoubleClicked); - d->buttons.append( button ); - } - - // rebuild toolbar shape and contents - d->reposition(); -} - -void PageViewToolBar::setSide( Side side ) -{ - d->anchorSide = side; - - d->reposition(); -} - -void PageViewToolBar::showAndAnimate() -{ - // set parameters for sliding in - d->hiding = false; - - show(); - -#ifdef OKULAR_ANIMATE_REVIEW_TOOBAR - // start scrolling in - d->animTimer->start( 20 ); -#else - d->currentPosition = d->endPosition; - - move( d->currentPosition ); - - d->visible = true; -#endif -} - -void PageViewToolBar::hideAndDestroy() -{ - // set parameters for sliding out - d->hiding = true; - d->endPosition = d->getOuterPoint(); - -#ifdef OKULAR_ANIMATE_REVIEW_TOOBAR - // start scrolling out - d->animTimer->start( 20 ); -#else - d->currentPosition = d->endPosition; - - move( d->currentPosition ); - - d->visible = false; - deleteLater(); -#endif -} - -void PageViewToolBar::selectButton( int id ) -{ - ToolBarButton * button = nullptr; - if ( id >= 0 && id < d->buttons.count() ) - button = *(d->buttons.begin() + id); - else - { - QLinkedList< ToolBarButton * >::const_iterator it = d->buttons.begin(), end = d->buttons.end(); - for ( ; !button && it != end; ++it ) - if ( (*it)->isChecked() ) - button = *it; - if ( button ) - button->setChecked( false ); - } - d->selectButton( button ); -} - -bool PageViewToolBar::eventFilter( QObject * obj, QEvent * e ) -{ - // if anchorWidget changed geometry reposition toolbar - if ( obj == d->anchorWidget && e->type() == QEvent::Resize ) - { - d->animTimer->stop(); - if ( d->hiding ) - deleteLater(); - else - d->reposition(); - } - - // don't block event - return false; -} - -void PageViewToolBar::paintEvent( QPaintEvent * e ) -{ - // paint the internal pixmap over the widget - QPainter p( this ); - p.drawImage( e->rect().topLeft(), d->backgroundPixmap.toImage(), e->rect() ); -} - -void PageViewToolBar::mousePressEvent( QMouseEvent * e ) -{ - // set 'dragging' cursor - if ( e->button() == Qt::LeftButton ) - setCursor( Qt::SizeAllCursor ); -} - -void PageViewToolBar::mouseMoveEvent( QMouseEvent * e ) -{ - if ( ( QApplication::mouseButtons() & Qt::LeftButton ) != Qt::LeftButton ) - return; - - // compute the nearest side to attach the widget to - QPoint parentPos = mapToParent( e->pos() ); - float nX = (float)parentPos.x() / (float)d->anchorWidget->width(), - nY = (float)parentPos.y() / (float)d->anchorWidget->height(); - if ( nX > 0.3 && nX < 0.7 && nY > 0.3 && nY < 0.7 ) - return; - bool LT = nX < (1.0 - nY); - bool LB = nX < (nY); - Side side = LT ? ( LB ? Left : Top ) : ( LB ? Bottom : Right ); - - // check if side changed - if ( side == d->anchorSide ) - return; - - d->anchorSide = side; - d->reposition(); - emit orientationChanged( (int)side ); -} - -void PageViewToolBar::mouseReleaseEvent( QMouseEvent * e ) -{ - // set normal cursor - if ( e->button() == Qt::LeftButton ) - setCursor( Qt::ArrowCursor ); -} - -void ToolBarPrivate::buildToolBar() -{ - int buttonsNumber = buttons.count(), - parentWidth = anchorWidget->width(), - parentHeight = anchorWidget->height(), - myCols = 1, - myRows = 1; - - // 1. find out columns and rows we're going to use - bool topLeft = anchorSide == PageViewToolBar::Left || anchorSide == PageViewToolBar::Top; - bool vertical = anchorSide == PageViewToolBar::Left || anchorSide == PageViewToolBar::Right; - if ( vertical ) - { - myCols = 1 + (buttonsNumber * toolBarGridSize) / - (parentHeight - toolBarGridSize); - myRows = (int)ceil( (float)buttonsNumber / (float)myCols ); - } - else - { - myRows = 1 + (buttonsNumber * toolBarGridSize) / - (parentWidth - toolBarGridSize); - myCols = (int)ceil( (float)buttonsNumber / (float)myRows ); - } - - // 2. compute widget size (from rows/cols) - int myWidth = myCols * toolBarGridSize, - myHeight = myRows * toolBarGridSize, - xOffset = (toolBarGridSize - ToolBarButton::buttonSize) / 2, - yOffset = (toolBarGridSize - ToolBarButton::buttonSize) / 2; - - if ( vertical ) - { - myHeight += 16; - myWidth += 4; - yOffset += 12; - if ( anchorSide == PageViewToolBar::Right ) - xOffset += 4; - } - else - { - myWidth += 16; - myHeight += 4; - xOffset += 12; - if ( anchorSide == PageViewToolBar::Bottom ) - yOffset += 4; - } - - bool prevUpdates = q->updatesEnabled(); - q->setUpdatesEnabled( false ); - - // 3. resize pixmap, mask and widget - QBitmap mask( myWidth + 1, myHeight + 1 ); - backgroundPixmap = QPixmap( myWidth + 1, myHeight + 1 ); - backgroundPixmap.fill(Qt::transparent); - q->resize( myWidth + 1, myHeight + 1 ); - - // 4. create and set transparency mask // 4. draw background - QPainter maskPainter( &mask); - mask.fill( Qt::white ); - maskPainter.setBrush( Qt::black ); - if ( vertical ) - maskPainter.drawRoundRect( topLeft ? -10 : 0, 0, myWidth + 11, myHeight, 2000 / (myWidth + 10), 2000 / myHeight ); - else - maskPainter.drawRoundRect( 0, topLeft ? -10 : 0, myWidth, myHeight + 11, 2000 / myWidth, 2000 / (myHeight + 10) ); - maskPainter.end(); - q->setMask( mask ); - - // 5. draw background - QPainter bufferPainter( &backgroundPixmap ); - bufferPainter.translate( 0.5, 0.5 ); - QPalette pal = q->palette(); - // 5.1. draw horizontal/vertical gradient - QLinearGradient grad; - switch ( anchorSide ) - { - case PageViewToolBar::Left: - grad = QLinearGradient( 0, 1, myWidth + 1, 1 ); - break; - case PageViewToolBar::Right: - grad = QLinearGradient( myWidth + 1, 1, 0, 1 ); - break; - case PageViewToolBar::Top: - grad = QLinearGradient( 1, 0, 1, myHeight + 1 ); - break; - case PageViewToolBar::Bottom: - grad = QLinearGradient( 1, myHeight + 1, 0, 1 ); - break; - } - grad.setColorAt( 0, pal.color( QPalette::Active, QPalette::Button ) ); - grad.setColorAt( 1, pal.color( QPalette::Active, QPalette::Light ) ); - bufferPainter.setBrush( QBrush( grad ) ); - // 5.2. draw rounded border - bufferPainter.setPen( pal.color( QPalette::Active, QPalette::Dark ).lighter( 140 ) ); - bufferPainter.setRenderHints( QPainter::Antialiasing ); - if ( vertical ) - bufferPainter.drawRoundRect( topLeft ? -10 : 0, 0, myWidth + 10, myHeight, 2000 / (myWidth + 10), 2000 / myHeight ); - else - bufferPainter.drawRoundRect( 0, topLeft ? -10 : 0, myWidth, myHeight + 10, 2000 / myWidth, 2000 / (myHeight + 10) ); - // 5.3. draw handle - bufferPainter.translate( -0.5, -0.5 ); - bufferPainter.setPen( pal.color( QPalette::Active, QPalette::Mid ) ); - if ( vertical ) - { - int dx = anchorSide == PageViewToolBar::Left ? 2 : 4; - bufferPainter.drawLine( dx, 6, dx + myWidth - 8, 6 ); - bufferPainter.drawLine( dx, 9, dx + myWidth - 8, 9 ); - bufferPainter.setPen( pal.color( QPalette::Active, QPalette::Light ) ); - bufferPainter.drawLine( dx + 1, 7, dx + myWidth - 7, 7 ); - bufferPainter.drawLine( dx + 1, 10, dx + myWidth - 7, 10 ); - } - else - { - int dy = anchorSide == PageViewToolBar::Top ? 2 : 4; - bufferPainter.drawLine( 6, dy, 6, dy + myHeight - 8 ); - bufferPainter.drawLine( 9, dy, 9, dy + myHeight - 8 ); - bufferPainter.setPen( pal.color( QPalette::Active, QPalette::Light ) ); - bufferPainter.drawLine( 7, dy + 1, 7, dy + myHeight - 7 ); - bufferPainter.drawLine( 10, dy + 1, 10, dy + myHeight - 7 ); - } - bufferPainter.end(); - - // 6. reposition buttons (in rows/col grid) - int gridX = 0, - gridY = 0; - QLinkedList< ToolBarButton * >::const_iterator it = buttons.begin(), end = buttons.end(); - for ( ; it != end; ++it ) - { - ToolBarButton * button = *it; - button->move( gridX * toolBarGridSize + xOffset, - gridY * toolBarGridSize + yOffset ); - button->show(); - if ( ++gridX == myCols ) - { - gridX = 0; - gridY++; - } - } - - q->setUpdatesEnabled( prevUpdates ); -} - -void ToolBarPrivate::reposition() -{ - // note: hiding widget here will gives better gfx, but ends drag operation - // rebuild widget and move it to its final place - buildToolBar(); - if ( !visible ) - { - currentPosition = getOuterPoint(); - endPosition = getInnerPoint(); - } - else - { - currentPosition = getInnerPoint(); - endPosition = getOuterPoint(); - } - q->move( currentPosition ); - - // repaint all buttons (to update background) - QLinkedList< ToolBarButton * >::const_iterator it = buttons.begin(), end = buttons.end(); - for ( ; it != end; ++it ) - (*it)->update(); -} - -QPoint ToolBarPrivate::getInnerPoint() const -{ - // returns the final position of the widget - QPoint newPos; - switch ( anchorSide ) - { - case PageViewToolBar::Left: - newPos = QPoint( 0, ( anchorWidget->height() - q->height() ) / 2 ); - break; - case PageViewToolBar::Top: - newPos = QPoint( ( anchorWidget->width() - q->width() ) / 2, 0 ); - break; - case PageViewToolBar::Right: - newPos = QPoint( anchorWidget->width() - q->width(), ( anchorWidget->height() - q->height() ) / 2 ); - break; - case PageViewToolBar::Bottom: - newPos = QPoint( ( anchorWidget->width() - q->width()) / 2, anchorWidget->height() - q->height() ); - break; - } - return newPos + anchorWidget->pos(); -} - -QPoint ToolBarPrivate::getOuterPoint() const -{ - // returns the point from which the transition starts - QPoint newPos; - switch ( anchorSide ) - { - case PageViewToolBar::Left: - newPos = QPoint( -q->width(), ( anchorWidget->height() - q->height() ) / 2 ); - break; - case PageViewToolBar::Top: - newPos = QPoint( ( anchorWidget->width() - q->width() ) / 2, -q->height() ); - break; - case PageViewToolBar::Right: - newPos = QPoint( anchorWidget->width(), ( anchorWidget->height() - q->height() ) / 2 ); - break; - case PageViewToolBar::Bottom: - newPos = QPoint( ( anchorWidget->width() - q->width() ) / 2, anchorWidget->height() ); - break; - } - return newPos + anchorWidget->pos(); -} - -void PageViewToolBar::slotAnimate() -{ - // move currentPosition towards endPosition - int dX = d->endPosition.x() - d->currentPosition.x(), - dY = d->endPosition.y() - d->currentPosition.y(); - dX = dX / 6 + qMax( -1, qMin( 1, dX) ); - dY = dY / 6 + qMax( -1, qMin( 1, dY) ); - d->currentPosition.setX( d->currentPosition.x() + dX ); - d->currentPosition.setY( d->currentPosition.y() + dY ); - - // move the widget - move( d->currentPosition ); - - // handle arrival to the end - if ( d->currentPosition == d->endPosition ) - { - d->animTimer->stop(); - if ( d->hiding ) - { - d->visible = false; - deleteLater(); - } - else - { - d->visible = true; - } - } -} - -void PageViewToolBar::slotButtonClicked() -{ - ToolBarButton * button = qobject_cast( sender() ); - d->selectButton( button ); -} - -void ToolBarPrivate::selectButton( ToolBarButton * button ) -{ - if ( button ) - { - // deselect other buttons - QLinkedList< ToolBarButton * >::const_iterator it = buttons.begin(), end = buttons.end(); - for ( ; it != end; ++it ) - if ( *it != button ) - (*it)->setChecked( false ); - // emit signal (-1 if button has been unselected) - emit q->toolSelected( button->isChecked() ? button->buttonID() : -1 ); - } -} - -void PageViewToolBar::setToolsEnabled( bool on ) -{ - QLinkedList< ToolBarButton * >::const_iterator it = d->buttons.begin(), end = d->buttons.end(); - for ( ; it != end; ++it ) - (*it)->setEnabled( on ); -} - -void PageViewToolBar::setTextToolsEnabled( bool on ) -{ - QLinkedList< ToolBarButton * >::const_iterator it = d->buttons.begin(), end = d->buttons.end(); - for ( ; it != end; ++it ) - if ( (*it)->isText() ) - (*it)->setEnabled( on ); -} - #include "moc_pageviewutils.cpp" diff --git a/ui/toolaction.cpp b/ui/toolaction.cpp --- a/ui/toolaction.cpp +++ b/ui/toolaction.cpp @@ -49,7 +49,7 @@ button->setFocusPolicy( Qt::NoFocus ); button->setIconSize( toolBar->iconSize() ); button->setToolButtonStyle( toolBar->toolButtonStyle() ); - button->setPopupMode( QToolButton::DelayedPopup ); + button->setPopupMode( QToolButton::MenuButtonPopup ); button->setMenu( new QMenu( button ) ); button->setCheckable( true ); connect(toolBar, &QToolBar::iconSizeChanged, button, &QToolButton::setIconSize);