1 #define ROUNDED_PIXEL 5
2 #define SHADOW_COLOR palette().highlight().color()
3 #define SHADOW_SIZE 20
4
5 #include "asemannativenotificationitem.h"
6
7 #include <QPainterPath>
8 #include <QPaintEvent>
9 #include <QSize>
10 #include <QPainter>
11 #include <QGraphicsBlurEffect>
12 #include <QLabel>
13 #include <QPushButton>
14 #include <QToolButton>
15 #include <QHBoxLayout>
16 #include <QVBoxLayout>
17 #include <QDesktopWidget>
18 #include <QApplication>
19 #include <QTimer>
20 #include <QPixmap>
21
22 class DialogBack: public QWidget
23 {
24 public:
DialogBack(QWidget * parent=0)25 DialogBack( QWidget *parent = 0 ): QWidget(parent){
26 effect = new QGraphicsBlurEffect(this);
27 effect->setBlurRadius(SHADOW_SIZE-10);
28 setGraphicsEffect(effect);
29 color = QColor(0,0,0,255);
30 }
31
setColor(const QColor & color)32 void setColor( const QColor & color ){
33 DialogBack::color = color;
34 repaint();
35 }
36
~DialogBack()37 ~DialogBack(){}
38
39 protected:
paintEvent(QPaintEvent * e)40 void paintEvent(QPaintEvent *e){
41 QPainter painter(this);
42 painter.setRenderHint( QPainter::Antialiasing , true );
43 painter.fillRect( e->rect(), color );
44 }
45
46 private:
47 QGraphicsBlurEffect *effect;
48 QColor color;
49 };
50
51 class DialogScene: public QWidget
52 {
53 public:
DialogScene(QWidget * parent=0)54 DialogScene( QWidget *parent = 0 ): QWidget(parent){ }
~DialogScene()55 ~DialogScene(){}
56
dialogPath(const QRect & rct,int padding) const57 QPainterPath dialogPath( const QRect & rct , int padding ) const
58 {
59 QPainterPath path;
60 path.setFillRule( Qt::WindingFill );
61
62 path.moveTo( rct.width()/2 , padding );
63 path.lineTo( rct.width()-padding-ROUNDED_PIXEL , padding );
64 path.quadTo( rct.width()-padding , padding , rct.width()-padding , padding+ROUNDED_PIXEL );
65 path.lineTo( rct.width()-padding , rct.height()-padding-ROUNDED_PIXEL );
66 path.quadTo( rct.width()-padding , rct.height()-padding , rct.width()-padding-ROUNDED_PIXEL , rct.height()-padding );
67 path.lineTo( padding+ROUNDED_PIXEL , rct.height()-padding );
68 path.quadTo( padding , rct.height()-padding , padding , rct.height()-padding-ROUNDED_PIXEL );
69 path.lineTo( padding , padding+ROUNDED_PIXEL );
70 path.quadTo( padding , padding , padding+ROUNDED_PIXEL , padding );
71 path.lineTo( rct.width()/2 , padding );
72
73 return path;
74 }
75
76 protected:
paintEvent(QPaintEvent * e)77 void paintEvent(QPaintEvent *e){
78 Q_UNUSED(e)
79 QPainter painter(this);
80 painter.setRenderHint( QPainter::Antialiasing , true );
81 painter.fillPath( dialogPath(rect(),0), QColor(255,255,255) );
82 }
83
84 private:
85 QGraphicsBlurEffect *effect;
86 };
87
88 class AsemanNativeNotificationItemPrivate
89 {
90 public:
91 DialogBack *back;
92 DialogScene *scene;
93
94 QColor shadow_color;
95
96 QVBoxLayout *layout;
97 QHBoxLayout *body_layout;
98 QVBoxLayout *btns_layout;
99 QHBoxLayout *ttle_layout;
100
101 QLabel *title_lbl;
102 QLabel *body_lbl;
103 QLabel *icon_lbl;
104
105 QList<QPushButton*> buttons;
106 QHash<QPushButton*,QString> actions;
107
108 QToolButton *close_btn;
109 };
110
111
AsemanNativeNotificationItem(QWidget * parent)112 AsemanNativeNotificationItem::AsemanNativeNotificationItem(QWidget *parent) :
113 QWidget(parent)
114 {
115 p = new AsemanNativeNotificationItemPrivate;
116 p->shadow_color = QColor( SHADOW_COLOR );
117
118 p->back = new DialogBack(this);
119 p->back->setColor( p->shadow_color );
120
121 p->scene = new DialogScene( this );
122
123 p->title_lbl = new QLabel();
124 p->title_lbl->setAlignment(Qt::AlignCenter);
125 p->title_lbl->setFixedHeight(26);
126
127 p->close_btn = new QToolButton();
128 p->close_btn->setText("X");
129 p->close_btn->setFixedSize(26, 26);
130 p->close_btn->setAutoRaise(true);
131
132 p->ttle_layout = new QHBoxLayout();
133 p->ttle_layout->addWidget(p->title_lbl);
134 p->ttle_layout->addWidget(p->close_btn);
135 p->ttle_layout->setContentsMargins(0,0,0,0);
136 p->ttle_layout->setSpacing(1);
137
138 p->icon_lbl = new QLabel();
139 p->icon_lbl->setFixedSize(64, 64);
140 p->icon_lbl->setScaledContents(true);
141
142 p->body_lbl = new QLabel();
143 p->body_lbl->setWordWrap(true);
144
145 p->btns_layout = new QVBoxLayout();
146 p->btns_layout->setContentsMargins(0,0,0,0);
147 p->btns_layout->setSpacing(1);
148
149 p->body_layout = new QHBoxLayout();
150 p->body_layout->addWidget(p->icon_lbl);
151 p->body_layout->addWidget(p->body_lbl, 10000);
152 p->body_layout->addLayout(p->btns_layout);
153 p->body_layout->setContentsMargins(0,0,0,0);
154 p->body_layout->setSpacing(8);
155
156 p->layout = new QVBoxLayout(this);
157 p->layout->addLayout(p->ttle_layout);
158 p->layout->addLayout(p->body_layout);
159 p->layout->setContentsMargins(SHADOW_SIZE+10,SHADOW_SIZE+8,SHADOW_SIZE+10,SHADOW_SIZE+8);
160 p->layout->setSpacing(1);
161
162 setWindowFlags( Qt::Window | Qt::FramelessWindowHint | Qt::ToolTip );
163 setAttribute(Qt::WA_TranslucentBackground);
164 setAttribute(Qt::WA_NoSystemBackground);
165 setAttribute(Qt::WA_DeleteOnClose);
166 setMouseTracking( true );
167 setWindowOpacity(0.9);
168
169 refreshSize();
170
171 connect(p->close_btn, SIGNAL(clicked()), SLOT(close()) );
172 }
173
setActions(const QStringList & actions)174 void AsemanNativeNotificationItem::setActions(const QStringList &actions)
175 {
176 for(int i=0; i<p->btns_layout->count(); i++)
177 delete p->btns_layout->takeAt(i);
178
179 for(int i=1 ;i<actions.count(); i+=2)
180 {
181 const QString &action = actions.at(i-1);
182 const QString &text = actions.at(i);
183
184 QPushButton *btn = new QPushButton();
185 btn->setText(text);
186
187 p->actions.insert(btn, action);
188 p->buttons << btn;
189
190 p->btns_layout->addWidget(btn);
191
192 connect(btn, SIGNAL(clicked()), SLOT(buttonClicked()) );
193 }
194
195 p->body_layout->addStretch();
196 }
197
setTitle(const QString & title)198 void AsemanNativeNotificationItem::setTitle(const QString &title)
199 {
200 p->title_lbl->setText(title);
201 }
202
setBody(const QString & body)203 void AsemanNativeNotificationItem::setBody(const QString &body)
204 {
205 p->body_lbl->setText(body.left(100) + "...");
206 }
207
setIcon(const QString & icon)208 void AsemanNativeNotificationItem::setIcon(const QString &icon)
209 {
210 p->icon_lbl->setPixmap( QPixmap(icon) );
211 }
212
setTimeOut(int timeOut)213 void AsemanNativeNotificationItem::setTimeOut(int timeOut)
214 {
215 if(timeOut == 0)
216 return;
217
218 QTimer::singleShot(timeOut, this, SLOT(close()) );
219 }
220
resizeEvent(QResizeEvent * e)221 void AsemanNativeNotificationItem::resizeEvent(QResizeEvent *e)
222 {
223 refreshSize();
224 QWidget::resizeEvent(e);
225 }
226
mouseReleaseEvent(QMouseEvent * e)227 void AsemanNativeNotificationItem::mouseReleaseEvent(QMouseEvent *e)
228 {
229 Q_UNUSED(e)
230 close();
231 }
232
refreshSize()233 void AsemanNativeNotificationItem::refreshSize()
234 {
235 QRect rect( SHADOW_SIZE, SHADOW_SIZE, width()-2*SHADOW_SIZE, height()-2*SHADOW_SIZE );
236
237 const QRect &scr = QApplication::desktop()->availableGeometry();
238
239 p->back->setGeometry( rect );
240 p->scene->setGeometry( rect );
241
242 move(scr.x()+scr.width()-width()+SHADOW_SIZE*0.7, scr.y()+scr.height()-height()+SHADOW_SIZE*0.7);
243 }
244
setRaised()245 void AsemanNativeNotificationItem::setRaised()
246 {
247 raise();
248 }
249
buttonClicked()250 void AsemanNativeNotificationItem::buttonClicked()
251 {
252 QPushButton *btn = static_cast<QPushButton*>(sender());
253 if(!btn)
254 return;
255
256 const QString &action = p->actions.value(btn);
257 emit actionTriggered(action);
258 }
259
~AsemanNativeNotificationItem()260 AsemanNativeNotificationItem::~AsemanNativeNotificationItem()
261 {
262 delete p;
263 }
264
265