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