1 /***************************************************************************
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 3 of the License, or *
6 * (at your option) any later version. *
7 * *
8 ***************************************************************************/
9
10 #include "TabButton.h"
11
12 #include <QResizeEvent>
13 #include <QLabel>
14 #include <QEvent>
15 #include <QMouseEvent>
16 #include <QStyleOptionButton>
17 #include <QApplication>
18 #include <QPaintEvent>
19 #include <QPainter>
20 #include <QStyleOption>
21 #include <QLinearGradient>
22 #include <QBrush>
23 #include <QPen>
24 #include <QPointF>
25 #include <QMimeData>
26 #include <QDrag>
27
28 #include "WulforUtil.h"
29 #include "WulforSettings.h"
30
31 #include <QDataStream>
32
33 static const int margin = 2;
34 static const int LABELWIDTH = 20;
35 static const int CLOSEPXWIDTH = 14;
36 static const int PXWIDTH = 16;
37
TabButton(QWidget * parent)38 TabButton::TabButton(QWidget *parent) :
39 QPushButton(parent), isLeftBtnHold(false)
40 {
41 setFlat(true);
42 setCheckable(true);
43 setAutoExclusive(true);
44 setAutoDefault(false);
45 setAcceptDrops(true);
46
47 parentHeight = QPushButton::sizeHint().height();
48
49 label = new QLabel(this);
50 label->setPixmap(WulforUtil::getInstance()->getPixmap(WulforUtil::eiEDITDELETE).scaled(CLOSEPXWIDTH, CLOSEPXWIDTH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
51 label->setFixedSize(QSize(LABELWIDTH, LABELWIDTH));
52 label->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
53
54 px_label = new QLabel(this);
55 px_label->setFixedSize(QSize(LABELWIDTH, LABELWIDTH));
56 px_label->setAlignment(Qt::AlignCenter | Qt::AlignVCenter);
57
58 installEventFilter(this);
59 label->installEventFilter(this);
60
61 updateGeometry();
62 }
63
resizeEvent(QResizeEvent * e)64 void TabButton::resizeEvent(QResizeEvent *e){
65 e->accept();
66
67 updateGeometry();
68 }
69
eventFilter(QObject * obj,QEvent * e)70 bool TabButton::eventFilter(QObject *obj, QEvent *e){
71 bool ret = QPushButton::eventFilter(obj, e);
72
73 if (e->type() == QEvent::MouseButtonRelease){
74 QMouseEvent *m_e = reinterpret_cast<QMouseEvent*>(e);
75
76 if ((m_e->button() == Qt::MidButton) || (childAt(m_e->pos()) == static_cast<QWidget*>(label)))
77 emit closeRequest();
78 }
79
80 return ret;
81 }
82
dragEnterEvent(QDragEnterEvent * event)83 void TabButton::dragEnterEvent(QDragEnterEvent *event){
84 if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
85 if (event->source() == this) {
86 event->setDropAction(Qt::MoveAction);
87 event->accept();
88 } else {
89 event->acceptProposedAction();
90 }
91 } else {
92 event->ignore();
93 }
94 }
95
dragMoveEvent(QDragMoveEvent * event)96 void TabButton::dragMoveEvent(QDragMoveEvent *event){
97 if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
98 if (event->source() == this) {
99 event->setDropAction(Qt::MoveAction);
100 event->accept();
101 } else {
102 event->acceptProposedAction();
103 }
104 } else {
105 event->ignore();
106 }
107 }
108
dropEvent(QDropEvent * e)109 void TabButton::dropEvent(QDropEvent *e){
110 if (qobject_cast<TabButton*>(e->source()) && this != qobject_cast<TabButton*>(e->source()))
111 emit dropped(qobject_cast<TabButton*>(e->source()));
112
113 e->ignore();
114 }
115
mousePressEvent(QMouseEvent * e)116 void TabButton::mousePressEvent(QMouseEvent *e){
117 QPushButton::mousePressEvent(e);
118
119 if (e->button() == Qt::LeftButton){
120 emit clicked();
121
122 isLeftBtnHold = true;
123 }
124 }
125
mouseMoveEvent(QMouseEvent * e)126 void TabButton::mouseMoveEvent(QMouseEvent *e){
127 if (!isLeftBtnHold){
128 QPushButton::mouseMoveEvent(e);
129
130 return;
131 }
132
133 QPixmap pxm = QPixmap::grabWidget(this, rect());
134
135 QByteArray data;
136 QDataStream stream(&data, QIODevice::WriteOnly);
137 stream << pxm << QPoint(mapFromGlobal(QCursor::pos()));
138
139 QMimeData *mimeData = new QMimeData();
140 mimeData->setData("application/x-dnditemdata", data);
141
142 QDrag *drag = new QDrag(this);
143 drag->setMimeData(mimeData);
144 drag->setPixmap(pxm);
145 drag->setHotSpot(mapFromGlobal(QCursor::pos()));
146
147 drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
148
149 e->accept();
150 }
151
mouseReleaseEvent(QMouseEvent * e)152 void TabButton::mouseReleaseEvent(QMouseEvent *e){
153 QPushButton::mouseReleaseEvent(e);
154
155 isLeftBtnHold = false;
156 }
157
paintEvent(QPaintEvent * e)158 void TabButton::paintEvent(QPaintEvent *e){
159 QStyleOptionButton option;
160 QPainter p(this);
161 initStyleOption(&option);
162
163 bool checked = (option.state & QStyle::State_On);
164 bool mouseOver = (option.state & QStyle::State_MouseOver);
165
166 option.state &= ~(QStyle::State_On|QStyle::State_MouseOver|QStyle::State_Enabled|
167 QStyle::State_HasFocus|QStyle::State_Active|QStyle::State_Sunken);//shutdown all states
168
169 qApp->style()->drawControl(QStyle::CE_PushButton, &option, &p);
170
171 auto getGradient = [&,this](const int centralFactor, const int sideFactor) -> QLinearGradient {
172 QLinearGradient gr(0, 0, this->width(), 0);
173
174 gr.setSpread(QGradient::PadSpread);
175 gr.setColorAt(0.00, this->palette().background().color());
176 gr.setColorAt(0.25, this->palette().highlight().color().lighter(sideFactor));
177 gr.setColorAt(0.50, this->palette().highlight().color().lighter(centralFactor));
178 gr.setColorAt(0.75, this->palette().highlight().color().lighter(sideFactor));
179 gr.setColorAt(1.00, this->palette().background().color());
180
181 return gr;
182 };
183
184 auto drawButtonLines = [&,this](const QLinearGradient &gr) -> void {
185 p.fillRect(0, 0, this->width(), 1, gr);
186 p.fillRect(0, this->height()-1, this->width(), 1, gr);
187 };
188
189 if (checked)
190 drawButtonLines( getGradient(100, 105) );
191 else if (mouseOver)
192 drawButtonLines( getGradient(105, 110) );
193
194 p.end();
195 }
196
sizeHint() const197 QSize TabButton::sizeHint() const {
198 ensurePolished();
199
200 int h = normalHeight();
201 int w = normalWidth();
202
203 return QSize(w, h);
204 }
205
normalWidth() const206 int TabButton::normalWidth() const {
207 QFontMetrics metrics = qApp->fontMetrics();
208
209 return LABELWIDTH*2+metrics.width(text())+margin*3;
210 }
211
normalHeight() const212 int TabButton::normalHeight() const {
213 return (LABELWIDTH+contentsMargins().top()+contentsMargins().bottom());
214 }
215
setWidgetIcon(const QPixmap & px)216 void TabButton::setWidgetIcon(const QPixmap &px){
217 px_label->setPixmap(px.scaled(PXWIDTH, PXWIDTH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
218 }
219
updateStyles()220 void TabButton::updateStyles() {
221 label->setStyleSheet(QString("QLabel { margin-left: %1; }").arg(margin));
222 px_label->setStyleSheet(QString("QLabel { margin-right: %1; }").arg(margin*2));
223
224 QString styleText_pressed = "QPushButton:checked {\n";
225 QString styleText_button = "QPushButton {\n";
226
227 if (WBGET(WB_APP_TBAR_SHOW_CL_BTNS)){
228 styleText_pressed += QString("padding-right: %1;\n padding-left: %1;\n").arg(LABELWIDTH);
229 styleText_button += QString("padding-right: %1;\n padding-left: %1;\n").arg(LABELWIDTH);
230 }
231 else{
232 styleText_pressed += QString("margin-right: %1;\n margin-left: %1;\n").arg(LABELWIDTH*6);
233 styleText_button += QString("margin-right: %1;\n margin-left: %1;\n").arg(LABELWIDTH*6);
234 }
235
236 styleText_button += "}\n";
237 styleText_pressed += "}\n";
238
239 setStyleSheet(styleText_button + styleText_pressed);
240 }
241
updateGeometry()242 void TabButton::updateGeometry() {
243 if (WBGET(WB_APP_TBAR_SHOW_CL_BTNS)){
244 if (!label->isVisible())
245 label->show();
246
247 label->setGeometry(width()-LABELWIDTH-margin*2, (height()-LABELWIDTH)/2, LABELWIDTH, LABELWIDTH);
248 }
249 else
250 label->hide();
251
252 px_label->setGeometry(margin*2, (height()-LABELWIDTH)/2, LABELWIDTH, LABELWIDTH);
253
254 updateStyles();
255 }
256
257