1 /*
2     SPDX-FileCopyrightText: 2007 Pino Toscano <pino@kde.org>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "presentationsearchbar.h"
8 
9 #include <qevent.h>
10 #include <qlayout.h>
11 #include <qpushbutton.h>
12 #include <qstyle.h>
13 #include <qstyleoption.h>
14 #include <qstylepainter.h>
15 #include <qtoolbutton.h>
16 
17 #include <KLocalizedString>
18 #include <QIcon>
19 
20 #include "searchlineedit.h"
21 
22 #define SNAP_DELTA 15
23 
24 class HandleDrag : public QWidget
25 {
26     Q_OBJECT
27 
28 public:
HandleDrag(QWidget * parent=Q_NULLPTR)29     explicit HandleDrag(QWidget *parent = Q_NULLPTR)
30         : QWidget(parent)
31     {
32         setCursor(Qt::SizeAllCursor);
33         setFixedWidth(style()->pixelMetric(QStyle::PM_ToolBarHandleExtent));
34     }
35 
paintEvent(QPaintEvent *)36     void paintEvent(QPaintEvent *) override
37     {
38         QStyleOption opt;
39         opt.initFrom(this);
40         opt.state |= QStyle::State_Horizontal;
41         QStylePainter p(this);
42         p.drawPrimitive(QStyle::PE_IndicatorToolBarHandle, opt);
43     }
44 };
45 
PresentationSearchBar(Okular::Document * document,QWidget * anchor,QWidget * parent)46 PresentationSearchBar::PresentationSearchBar(Okular::Document *document, QWidget *anchor, QWidget *parent)
47     : QWidget(parent)
48     , m_anchor(anchor)
49     , m_snapped(true)
50 {
51     setAutoFillBackground(true);
52 
53     QHBoxLayout *lay = new QHBoxLayout(this);
54     lay->setContentsMargins(0, 0, 0, 0);
55 
56     m_handle = new HandleDrag(this);
57     m_handle->installEventFilter(this);
58     lay->addWidget(m_handle);
59 
60     QToolButton *closeBtn = new QToolButton(this);
61     closeBtn->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close")));
62     closeBtn->setIconSize(QSize(24, 24));
63     closeBtn->setToolTip(i18n("Close"));
64     closeBtn->setAutoRaise(true);
65     lay->addWidget(closeBtn);
66 
67     m_search = new SearchLineEdit(this, document);
68     m_search->setClearButtonEnabled(true);
69     m_search->setSearchCaseSensitivity(Qt::CaseInsensitive);
70     m_search->setSearchMinimumLength(0);
71     m_search->setSearchType(Okular::Document::NextMatch);
72     m_search->setSearchId(PRESENTATION_SEARCH_ID);
73     m_search->setSearchColor(qRgb(255, 255, 64));
74     m_search->setSearchMoveViewport(true);
75     lay->addWidget(m_search);
76 
77     QPushButton *findNextBtn = new QPushButton(QIcon::fromTheme(QStringLiteral("go-down-search")), i18n("Find Next"), this);
78     lay->addWidget(findNextBtn);
79 
80     m_anchor->installEventFilter(this);
81 
82     connect(closeBtn, &QAbstractButton::clicked, this, &QWidget::close);
83     connect(findNextBtn, &QPushButton::clicked, m_search, &SearchLineEdit::findNext);
84 }
85 
~PresentationSearchBar()86 PresentationSearchBar::~PresentationSearchBar()
87 {
88 }
89 
forceSnap()90 void PresentationSearchBar::forceSnap()
91 {
92     m_point = QPoint(m_anchor->width() / 2, m_anchor->height());
93     m_snapped = true;
94     move(m_point.x() - width() / 2, m_point.y() - height());
95 }
96 
focusOnSearchEdit()97 void PresentationSearchBar::focusOnSearchEdit()
98 {
99     m_search->setFocus();
100 }
101 
resizeEvent(QResizeEvent *)102 void PresentationSearchBar::resizeEvent(QResizeEvent *)
103 {
104     // if in snap mode, then force the snap and place ourselves correctly again
105     if (m_snapped)
106         forceSnap();
107 }
108 
eventFilter(QObject * obj,QEvent * e)109 bool PresentationSearchBar::eventFilter(QObject *obj, QEvent *e)
110 {
111     if (obj == m_handle && (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonRelease || e->type() == QEvent::MouseMove)) {
112         QMouseEvent *me = (QMouseEvent *)e;
113         if (e->type() == QEvent::MouseButtonPress) {
114             m_drag = m_handle->mapTo(this, me->pos());
115         } else if (e->type() == QEvent::MouseButtonRelease) {
116             m_drag = QPoint();
117         } else if (e->type() == QEvent::MouseMove) {
118             QPoint snapdelta(width() / 2, height());
119             QPoint delta = m_handle->mapTo(this, me->pos()) - m_drag;
120             QPoint newpostemp = pos() + delta;
121             QPoint tmp = newpostemp + snapdelta - m_point;
122             QPoint newpos = abs(tmp.x()) < SNAP_DELTA && abs(tmp.y()) < SNAP_DELTA ? m_point - snapdelta : newpostemp;
123             m_snapped = newpos == (m_point - snapdelta);
124             move(newpos);
125         }
126         return true;
127     }
128     if (obj == m_anchor && e->type() == QEvent::Resize) {
129         m_point = QPoint(m_anchor->width() / 2, m_anchor->height());
130 
131         if (m_snapped)
132             move(m_point.x() - width() / 2, m_point.y() - height());
133     }
134 
135     return false;
136 }
137 
138 #include "presentationsearchbar.moc"
139