1 /*****************************************************************************
2 * Copyright 2007 - 2010 Craig Drummond <craig.p.drummond@gmail.com> *
3 * Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com> *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU Lesser General Public License as *
7 * published by the Free Software Foundation; either version 2.1 of the *
8 * License, or (at your option) version 3, or any later version accepted *
9 * by the membership of KDE e.V. (or its successor approved by the *
10 * membership of KDE e.V.), which shall act as a proxy defined in *
11 * Section 6 of version 3 of the license. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16 * Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this library. If not, *
20 * see <http://www.gnu.org/licenses/>. *
21 *****************************************************************************/
22
23 #include "qtcurve_p.h"
24 #include "utils.h"
25
26 #include <QToolBar>
27 #include <QToolButton>
28 #include <QAbstractItemView>
29 #include <QDialog>
30 #include <QSplitter>
31 #include <QMdiSubWindow>
32 #include <QMainWindow>
33 #include <QComboBox>
34 #include <QTreeView>
35 #include <QGroupBox>
36 #include <QListView>
37 #include <QCheckBox>
38 #include <QRadioButton>
39 #include <QTextEdit>
40 #include <QDial>
41 #include <QLabel>
42 #include <QStackedLayout>
43 #include <QMenuBar>
44 #include <QMouseEvent>
45 #include <QScrollBar>
46 #include <QWizard>
47 #include <QDialogButtonBox>
48 #include <QPushButton>
49 #include <QHeaderView>
50 #include <QLineEdit>
51 #include <QSpinBox>
52 #include <QDir>
53 #include <QSettings>
54 #include <QPixmapCache>
55 #include <QTextStream>
56
57 #include "shadowhelper.h"
58 #include <qtcurve-utils/x11qtc.h>
59 #include <qtcurve-utils/qtutils.h>
60 #include <sys/time.h>
61
62 namespace QtCurve {
63
64 static const char *constBoldProperty = "qtc-set-bold";
65
66 bool
blendOOMenuHighlight(const QPalette & pal,const QColor & highlight)67 blendOOMenuHighlight(const QPalette &pal, const QColor &highlight)
68 {
69 QColor text(pal.text().color());
70 QColor hl(pal.highlightedText().color());
71
72 return ((text.red() < 50) && (text.green() < 50) && (text.blue() < 50) &&
73 (hl.red() > 127) && (hl.green() > 127) && (hl.blue() > 127) &&
74 TOO_DARK(highlight));
75 }
76
isNoEtchWidget(const QWidget * widget)77 bool isNoEtchWidget(const QWidget *widget)
78 {
79 if (theThemedApp == APP_KRUNNER) {
80 return true;
81 }
82 if (theThemedApp == APP_PLASMA) {
83 const QWidget *top = widget->window();
84
85 return !top || (!qobject_cast<const QDialog*>(top) &&
86 !qobject_cast<const QMainWindow*>(top));
87 }
88
89 if (widget && widget->inherits("QWebView")) {
90 return true;
91 }
92 // KHTML: widget -> QWidget -> QWidget -> KHTMLView
93 const QObject *w = (widget && widget->parent() &&
94 widget->parent()->parent() ?
95 widget->parent()->parent()->parent() : nullptr);
96
97 return ((w && isA(w, "KHTMLView")) ||
98 (widget && isInQAbstractItemView(widget->parentWidget())));
99 }
100
101 void
setOpacityProp(QWidget * w,unsigned short opacity)102 setOpacityProp(QWidget *w, unsigned short opacity)
103 {
104 // DO NOT condition compile on QTC_ENABLE_X11.
105 // There's no direct linkage on X11 and the following code will just do
106 // nothing if X11 is not enabled (either at compile time or at run time).
107 QTC_RET_IF_FAIL(qtcX11Enabled());
108 if (WId wid = qtcGetWid(w->window())) {
109 qtcX11SetOpacity(wid, opacity);
110 }
111 }
112
113 void
setBgndProp(QWidget * w,EAppearance app,bool haveBgndImage)114 setBgndProp(QWidget *w, EAppearance app, bool haveBgndImage)
115 {
116 // DO NOT condition compile on QTC_ENABLE_X11.
117 // There's no direct linkage on X11 and the following code will just do
118 // nothing if X11 is not enabled (either at compile time or at run time).
119 QTC_RET_IF_FAIL(qtcX11Enabled());
120 if (WId wid = qtcGetWid(w->window())) {
121 uint32_t prop = (((qtcIsFlatBgnd(app) ?
122 (haveBgndImage ? APPEARANCE_RAISED :
123 APPEARANCE_FLAT) : app) & 0xFF) |
124 (w->palette().background().color().rgb() &
125 0x00FFFFFF) << 8);
126 qtcX11SetBgnd(wid, prop);
127 }
128 }
129
setSbProp(QWidget * w)130 void setSbProp(QWidget *w)
131 {
132 // DO NOT condition compile on QTC_ENABLE_X11.
133 // There's no direct linkage on X11 and the following code will just do
134 // nothing if X11 is not enabled (either at compile time or at run time).
135 QTC_RET_IF_FAIL(qtcX11Enabled());
136 if (WId wid = qtcGetWid(w->window())) {
137 static const char *constStatusBarProperty = "qtcStatusBar";
138 QVariant prop(w->property(constStatusBarProperty));
139
140 if (!prop.isValid() || !prop.toBool()) {
141 w->setProperty(constStatusBarProperty, true);
142 qtcX11SetStatusBar(wid);
143 }
144 }
145 }
146
147 void
setBold(QWidget * widget)148 setBold(QWidget *widget)
149 {
150 QVariant prop(widget->property(constBoldProperty));
151 if (!prop.isValid() || !prop.toBool()) {
152 QFont font(widget->font());
153 if (!font.bold()) {
154 font.setBold(true);
155 widget->setFont(font);
156 widget->setProperty(constBoldProperty, true);
157 }
158 }
159 }
160
161 void
unSetBold(QWidget * widget)162 unSetBold(QWidget *widget)
163 {
164 QVariant prop(widget->property(constBoldProperty));
165 if (prop.isValid() && prop.toBool()) {
166 QFont font(widget->font());
167 font.setBold(false);
168 widget->setFont(font);
169 widget->setProperty(constBoldProperty, false);
170 }
171 }
172
173 QWidget*
scrollViewFrame(QWidget * widget)174 scrollViewFrame(QWidget *widget)
175 {
176 QWidget *w = widget;
177
178 for (int i = 0; i < 10 && w;i++, w = w->parentWidget()) {
179 if ((qobject_cast<QFrame*>(w) &&
180 ((QFrame*)w)->frameWidth() > 0) ||
181 qobject_cast<QTabWidget*>(w)) {
182 return w;
183 }
184 }
185 return nullptr;
186 }
187
188 QToolBar*
getToolBarChild(QWidget * w)189 getToolBarChild(QWidget *w)
190 {
191 for (QObject *child: w->children()) {
192 if (child->isWidgetType()) {
193 if (qobject_cast<QToolBar*>(child))
194 return static_cast<QToolBar*>(child);
195 QToolBar *tb = getToolBarChild((QWidget*)child);
196 if (tb) {
197 return tb;
198 }
199 }
200 }
201
202 return nullptr;
203 }
204
205 void
setStyleRecursive(QWidget * w,QStyle * s,int minSize)206 setStyleRecursive(QWidget *w, QStyle *s, int minSize)
207 {
208 w->setStyle(s);
209 if (qobject_cast<QToolButton*>(w))
210 w->setMinimumSize(1, minSize);
211
212 for (QObject *child: w->children()) {
213 if (child->isWidgetType()) {
214 setStyleRecursive((QWidget*)child, s, minSize);
215 }
216 }
217 }
218
219 //
220 // QtCurve's menu's have a 2 pixel border all around - but want the top,
221 // and left edges to active the nearest menu item. Therefore, when we get a
222 // mouse event in that region then adjsut its position...
223 bool
updateMenuBarEvent(QMouseEvent * event,QMenuBar * menu)224 updateMenuBarEvent(QMouseEvent *event, QMenuBar *menu)
225 {
226 struct HackEvent: public QMouseEvent {
227 bool
228 adjust()
229 {
230 if (l.x() < 2 || l.y() < 2) {
231 l = QPointF(l.x() < 2 ? l.x() + 2 : l.x(),
232 l.y() < 2 ? l.y() + 2 : l.y());
233 s = QPointF(l.x() < 2 ? s.x() + 2 : s.x(),
234 l.y() < 2 ? s.y() + 2 : s.y());
235 return true;
236 }
237 return false;
238 }
239 };
240
241 if (((HackEvent*)event)->adjust()) {
242 static_cast<QObject*>(menu)->event(event);
243 return true;
244 }
245 return false;
246 }
247
248 QRegion
windowMask(const QRect & r,bool full)249 windowMask(const QRect &r, bool full)
250 {
251 int x, y, w, h;
252 r.getRect(&x, &y, &w, &h);
253
254 if (full) {
255 QRegion region(x + 4, y + 0, w-4*2, h-0*2);
256 region += QRegion(x + 0, y + 4, w-0*2, h-4*2);
257 region += QRegion(x + 2, y + 1, w-2*2, h-1*2);
258 region += QRegion(x + 1, y + 2, w-1*2, h-2*2);
259 return region;
260 } else {
261 QRegion region(x+1, y+1, w-2, h-2);
262 region += QRegion(x, y+2, w, h-4);
263 region += QRegion(x+2, y, w-4, h);
264 return region;
265 }
266 }
267
268 const QWidget*
getWidget(const QPainter * p)269 getWidget(const QPainter *p)
270 {
271 if(p) {
272 if (QInternal::Widget==p->device()->devType()) {
273 return static_cast<const QWidget *>(p->device());
274 } else {
275 QPaintDevice *dev = QPainter::redirected(p->device());
276 if (dev && QInternal::Widget==dev->devType()) {
277 return static_cast<const QWidget *>(dev);
278 }
279 }
280 }
281 return nullptr;
282 }
283
284 const QImage*
getImage(const QPainter * p)285 getImage(const QPainter *p)
286 {
287 return (p && p->device() && QInternal::Image==p->device()->devType() ?
288 static_cast<const QImage*>(p->device()) : nullptr);
289 }
290
291 const QAbstractButton*
getButton(const QWidget * w,const QPainter * p)292 getButton(const QWidget *w, const QPainter *p)
293 {
294 const QWidget *widget = w ? w : getWidget(p);
295 return widget ? qobject_cast<const QAbstractButton*>(widget) : nullptr;
296 }
297
298 void
drawDots(QPainter * p,const QRect & r,bool horiz,int nLines,int offset,const QColor * cols,int startOffset,int dark)299 drawDots(QPainter *p, const QRect &r, bool horiz, int nLines, int offset,
300 const QColor *cols, int startOffset, int dark)
301 {
302 int space((nLines*2)+(nLines-1)),
303 x(horiz ? r.x() : r.x()+((r.width()-space)>>1)),
304 y(horiz ? r.y()+((r.height()-space)>>1) : r.y()),
305 i, j,
306 numDots((horiz ? (r.width()-(2*offset))/3 : (r.height()-(2*offset))/3)+1);
307
308 p->setRenderHint(QPainter::Antialiasing, true);
309 if (horiz) {
310 if(startOffset && y+startOffset>0)
311 y+=startOffset;
312
313 p->setPen(cols[dark]);
314 for(i=0; i<space; i+=3)
315 for(j=0; j<numDots; j++)
316 drawAaPoint(p, x+offset+(3*j), y+i);
317
318 p->setPen(cols[0]);
319 for(i=1; i<space; i+=3)
320 for(j=0; j<numDots; j++)
321 drawAaPoint(p, x+offset+1+(3*j), y+i);
322 } else {
323 if(startOffset && x+startOffset>0)
324 x+=startOffset;
325
326 p->setPen(cols[dark]);
327 for(i=0; i<space; i+=3)
328 for(j=0; j<numDots; j++)
329 drawAaPoint(p, x+i, y+offset+(3*j));
330
331 p->setPen(cols[0]);
332 for(i=1; i<space; i+=3)
333 for(j=0; j<numDots; j++)
334 drawAaPoint(p, x+i, y+offset+1+(3*j));
335 }
336 QPAINTER_RENDERHINT_AA_MAYBE_OFF(p);
337 }
338
339 bool
isInQAbstractItemView(const QObject * w)340 isInQAbstractItemView(const QObject *w)
341 {
342 int level = 8;
343 while (w && --level > 0) {
344 if (qobject_cast<const QAbstractItemView*>(w))
345 return true;
346 if (qobject_cast<const QDialog*>(w)
347 /* || qobject_cast<const QMainWindow *>(w)*/)
348 return false;
349 w = w->parent();
350 }
351 return false;
352 }
353
354 const QToolBar*
getToolBar(const QWidget * w)355 getToolBar(const QWidget *w)
356 {
357 return (w ? qobject_cast<const QToolBar*>(w) ?
358 static_cast<const QToolBar*>(w) :
359 getToolBar(w->parentWidget()) : nullptr);
360 }
361
362 void
drawTbArrow(const QStyle * style,const QStyleOptionToolButton * toolbutton,const QRect & rect,QPainter * painter,const QWidget * widget)363 drawTbArrow(const QStyle *style, const QStyleOptionToolButton *toolbutton,
364 const QRect &rect, QPainter *painter, const QWidget *widget)
365 {
366 QStyle::PrimitiveElement pe;
367 switch (toolbutton->arrowType) {
368 case Qt::LeftArrow:
369 pe = QStyle::PE_IndicatorArrowLeft;
370 break;
371 case Qt::RightArrow:
372 pe = QStyle::PE_IndicatorArrowRight;
373 break;
374 case Qt::UpArrow:
375 pe = QStyle::PE_IndicatorArrowUp;
376 break;
377 case Qt::DownArrow:
378 pe = QStyle::PE_IndicatorArrowDown;
379 break;
380 default:
381 return;
382 }
383
384 QStyleOption arrowOpt;
385 arrowOpt.rect = rect;
386 arrowOpt.palette = toolbutton->palette;
387 arrowOpt.state = toolbutton->state;
388 style->drawPrimitive(pe, &arrowOpt, painter, widget);
389 }
390
391 void
adjustToolbarButtons(const QWidget * widget,const QToolBar * toolbar,int & leftAdjust,int & topAdjust,int & rightAdjust,int & bottomAdjust,int & round)392 adjustToolbarButtons(const QWidget *widget, const QToolBar *toolbar,
393 int &leftAdjust, int &topAdjust, int &rightAdjust,
394 int &bottomAdjust, int &round)
395 {
396 const int constAdjust=6;
397 const int d = 1;
398 QRect geo(widget->geometry());
399 if (toolbar->orientation() == Qt::Horizontal) {
400 bool haveLeft =
401 qobject_cast<QToolButton*>(toolbar->childAt(geo.x() -
402 d, geo.y()));
403 bool haveRight =
404 qobject_cast<QToolButton*>(toolbar->childAt(geo.right() +
405 d, geo.y()));
406
407 if (haveLeft && haveRight) {
408 leftAdjust = -constAdjust;
409 rightAdjust = constAdjust;
410 round = ROUNDED_NONE;
411 } else if (haveLeft) {
412 leftAdjust = -constAdjust;
413 round = ROUNDED_RIGHT;
414 } else if (haveRight) {
415 rightAdjust = constAdjust;
416 round = ROUNDED_LEFT;
417 }
418 } else {
419 bool haveTop =
420 qobject_cast<QToolButton*>(toolbar->childAt(geo.x(), geo.y() - d));
421 bool haveBot =
422 qobject_cast<QToolButton*>(toolbar->childAt(geo.x(),
423 geo.bottom() + d));
424 if (haveTop && haveBot) {
425 topAdjust = -constAdjust;
426 bottomAdjust = constAdjust;
427 round = ROUNDED_NONE;
428 } else if (haveTop) {
429 topAdjust = -constAdjust;
430 round = ROUNDED_BOTTOM;
431 } else if (haveBot) {
432 bottomAdjust = constAdjust;
433 round = ROUNDED_TOP;
434 }
435 }
436 }
437
438 bool
isA(const QObject * w,const char * type)439 isA(const QObject *w, const char *type)
440 {
441 return (w && (0 == strcmp(w->metaObject()->className(), type) ||
442 (w->parent() &&
443 0 == strcmp(w->parent()->metaObject()->className(), type))));
444 }
445
446 }
447