1 /*
2   SPDX-FileCopyrightText: 2008-2014 Eike Hein <hein@kde.org>
3   SPDX-FileCopyrightText: 2020 Ryan McCoskrie <work@ryanmccoskrie.me>
4 
5   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
6 */
7 
8 #include "titlebar.h"
9 #include "mainwindow.h"
10 #include "skin.h"
11 
12 #include <KLocalizedString>
13 #include <QFontDatabase>
14 #include <QMenu>
15 #include <QPushButton>
16 
17 #include <QApplication>
18 #include <QBitmap>
19 #include <QPainter>
20 
TitleBar(MainWindow * mainWindow)21 TitleBar::TitleBar(MainWindow *mainWindow)
22     : QWidget(mainWindow)
23 {
24     setWhatsThis(xi18nc("@info:whatsthis",
25                         "<title>Title Bar</title>"
26                         "<para>The title bar displays the session title if available.</para>"));
27 
28     setAttribute(Qt::WA_OpaquePaintEvent);
29 
30     m_mainWindow = mainWindow;
31     m_skin = mainWindow->skin();
32 
33     setCursor(Qt::SizeVerCursor);
34 
35     m_focusButton = new QPushButton(this);
36     m_focusButton->setFocusPolicy(Qt::NoFocus);
37     m_focusButton->setCheckable(true);
38     m_focusButton->setToolTip(xi18nc("@info:tooltip", "Keep window open when it loses focus"));
39     m_focusButton->setWhatsThis(xi18nc("@info:whatsthis", "If this is checked, the window will stay open when it loses focus."));
40     m_focusButton->setCursor(Qt::ArrowCursor);
41     connect(m_focusButton, SIGNAL(toggled(bool)), mainWindow, SLOT(setKeepOpen(bool)));
42 
43     m_menuButton = new QPushButton(this);
44     m_menuButton->setFocusPolicy(Qt::NoFocus);
45     m_menuButton->setMenu(mainWindow->menu());
46     m_menuButton->setToolTip(xi18nc("@info:tooltip", "Open Menu"));
47     m_menuButton->setWhatsThis(xi18nc("@info:whatsthis", "Opens the main menu."));
48     m_menuButton->setCursor(Qt::ArrowCursor);
49 
50     m_quitButton = new QPushButton(this);
51     m_quitButton->setFocusPolicy(Qt::NoFocus);
52     m_quitButton->setToolTip(xi18nc("@info:tooltip Quits the application", "Quit"));
53     m_quitButton->setWhatsThis(xi18nc("@info:whatsthis", "Quits the application."));
54     m_quitButton->setCursor(Qt::ArrowCursor);
55     connect(m_quitButton, SIGNAL(clicked()), mainWindow, SLOT(close()));
56 }
57 
~TitleBar()58 TitleBar::~TitleBar()
59 {
60 }
61 
setVisible(bool visible)62 void TitleBar::setVisible(bool visible)
63 {
64     m_visible = visible;
65     if (m_visible) {
66         resize(width(), m_skin->titleBarBackgroundImage().height());
67     } else {
68         resize(width(), 0);
69     }
70 
71     QWidget::setVisible(m_visible);
72 }
73 
applySkin()74 void TitleBar::applySkin()
75 {
76     resize(width(), m_visible ? m_skin->titleBarBackgroundImage().height() : 0);
77 
78     m_focusButton->setStyleSheet(m_skin->titleBarFocusButtonStyleSheet());
79     m_menuButton->setStyleSheet(m_skin->titleBarMenuButtonStyleSheet());
80     m_quitButton->setStyleSheet(m_skin->titleBarQuitButtonStyleSheet());
81 
82     moveButtons();
83 
84     repaint();
85 
86     updateMask();
87 }
88 
moveButtons()89 void TitleBar::moveButtons()
90 {
91     if (m_skin->titleBarFocusButtonAnchor() == Qt::AnchorLeft)
92         m_focusButton->move(m_skin->titleBarFocusButtonPosition().x(), m_skin->titleBarFocusButtonPosition().y());
93     else if (m_skin->titleBarFocusButtonAnchor() == Qt::AnchorRight)
94         m_focusButton->move(width() - m_skin->titleBarFocusButtonPosition().x(), m_skin->titleBarFocusButtonPosition().y());
95 
96     if (m_skin->titleBarMenuButtonAnchor() == Qt::AnchorLeft)
97         m_menuButton->move(m_skin->titleBarMenuButtonPosition().x(), m_skin->titleBarMenuButtonPosition().y());
98     else if (m_skin->titleBarMenuButtonAnchor() == Qt::AnchorRight)
99         m_menuButton->move(width() - m_skin->titleBarMenuButtonPosition().x(), m_skin->titleBarMenuButtonPosition().y());
100 
101     if (m_skin->titleBarQuitButtonAnchor() == Qt::AnchorLeft)
102         m_quitButton->move(m_skin->titleBarQuitButtonPosition().x(), m_skin->titleBarQuitButtonPosition().y());
103     else if (m_skin->titleBarQuitButtonAnchor() == Qt::AnchorRight)
104         m_quitButton->move(width() - m_skin->titleBarQuitButtonPosition().x(), m_skin->titleBarQuitButtonPosition().y());
105 }
106 
resizeEvent(QResizeEvent * event)107 void TitleBar::resizeEvent(QResizeEvent *event)
108 {
109     moveButtons();
110 
111     updateMask();
112 
113     QWidget::resizeEvent(event);
114 }
115 
paintEvent(QPaintEvent *)116 void TitleBar::paintEvent(QPaintEvent *)
117 {
118     QPainter painter(this);
119     painter.setPen(m_skin->titleBarTextColor());
120 
121     const QPixmap &backgroundImage = m_skin->titleBarBackgroundImage();
122     const QPixmap &leftCornerImage = m_skin->titleBarLeftCornerImage();
123     const QPixmap &rightCornerImage = m_skin->titleBarRightCornerImage();
124 
125     painter.drawTiledPixmap(leftCornerImage.width(), 0, width() - leftCornerImage.width() - rightCornerImage.width(), height(), backgroundImage);
126 
127     painter.drawPixmap(0, 0, leftCornerImage);
128     painter.drawPixmap(width() - rightCornerImage.width(), 0, rightCornerImage);
129 
130     QFont font = QFontDatabase::systemFont(QFontDatabase::TitleFont);
131     font.setBold(m_skin->titleBarTextBold());
132     painter.setFont(font);
133 
134     const QString title = this->title();
135     if (m_skin->titleBarTextCentered()
136         && width() > m_skin->titleBarTextPosition().x() + painter.fontMetrics().horizontalAdvance(title) + m_focusButton->width() + m_quitButton->width()
137                 + m_menuButton->width())
138         painter.drawText(0, 0, width(), height(), Qt::AlignCenter, title);
139     else
140         painter.drawText(m_skin->titleBarTextPosition(), title);
141 
142     painter.end();
143 }
144 
mouseMoveEvent(QMouseEvent * event)145 void TitleBar::mouseMoveEvent(QMouseEvent *event)
146 {
147     if (event->buttons() == Qt::LeftButton) {
148         // Dynamic cast needed to use getDesktopGeometry()
149         MainWindow *window = dynamic_cast<MainWindow *>(parent());
150 
151         int maxHeight = window->getDesktopGeometry().height();
152         int newHeight = event->globalY() / (maxHeight / 100);
153 
154         // Correct newHeight if mouse is dragged too far
155         if (newHeight > 100) {
156             newHeight = 100;
157         } else if (newHeight < 10) {
158             newHeight = 10;
159         }
160 
161         window->setWindowHeight(newHeight);
162     } else {
163         QWidget::mouseMoveEvent(event);
164     }
165 }
166 
updateMask()167 void TitleBar::updateMask()
168 {
169     const QPixmap &leftCornerImage = m_skin->titleBarLeftCornerImage();
170     const QPixmap &rightCornerImage = m_skin->titleBarRightCornerImage();
171 
172     QRegion leftCornerRegion = leftCornerImage.hasAlpha() ? QRegion(leftCornerImage.mask()) : QRegion(leftCornerImage.rect());
173     QRegion rightCornerRegion = rightCornerImage.hasAlpha() ? QRegion(rightCornerImage.mask()) : QRegion(rightCornerImage.rect());
174 
175     QRegion mask = leftCornerRegion;
176 
177     mask += QRegion(QRect(0, 0, width() - leftCornerImage.width() - rightCornerImage.width(), height())).translated(leftCornerImage.width(), 0);
178 
179     mask += rightCornerRegion.translated(width() - rightCornerImage.width(), 0);
180 
181     setMask(mask);
182 }
183 
updateMenu()184 void TitleBar::updateMenu()
185 {
186     m_menuButton->setMenu(m_mainWindow->menu());
187 }
188 
setFocusButtonState(bool checked)189 void TitleBar::setFocusButtonState(bool checked)
190 {
191     m_focusButton->setChecked(checked);
192 }
193 
title()194 QString TitleBar::title()
195 {
196     if (!m_skin->titleBarText().isEmpty() && !m_title.isEmpty())
197         return m_title + QStringLiteral(" - ") + m_skin->titleBarText();
198     else if (!m_skin->titleBarText().isEmpty() && m_title.isEmpty())
199         return m_skin->titleBarText();
200     else
201         return m_title;
202 }
203 
setTitle(const QString & title)204 void TitleBar::setTitle(const QString &title)
205 {
206     m_title = title;
207 
208     repaint();
209 }
210