File indexing completed on 2024-04-14 05:39:55
0001 /***************************************************************************** 0002 * Copyright 2003 - 2010 Craig Drummond <craig.p.drummond@gmail.com> * 0003 * Copyright 2013 - 2015 Yichao Yu <yyc1992@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU Lesser General Public License as * 0007 * published by the Free Software Foundation; either version 2.1 of the * 0008 * License, or (at your option) version 3, or any later version accepted * 0009 * by the membership of KDE e.V. (or its successor approved by the * 0010 * membership of KDE e.V.), which shall act as a proxy defined in * 0011 * Section 6 of version 3 of the license. * 0012 * * 0013 * This program is distributed in the hope that it will be useful, * 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 0016 * Lesser General Public License for more details. * 0017 * * 0018 * You should have received a copy of the GNU Lesser General Public * 0019 * License along with this library. If not, * 0020 * see <http://www.gnu.org/licenses/>. * 0021 *****************************************************************************/ 0022 0023 #include "config.h" 0024 0025 #include "drawing.h" 0026 0027 #include "qt_settings.h" 0028 #include "helpers.h" 0029 #include "pixcache.h" 0030 #include "entry.h" 0031 #include "tab.h" 0032 #include "animation.h" 0033 0034 #include <qtcurve-utils/gtkprops.h> 0035 #include <qtcurve-utils/color.h> 0036 #include <qtcurve-utils/log.h> 0037 0038 #include <common/config_file.h> 0039 0040 namespace QtCurve { 0041 0042 #if GTK_CHECK_VERSION(2, 90, 0) 0043 static cairo_region_t* 0044 windowMask(int x, int y, int w, int h, bool full) 0045 { 0046 QtcRect rects[4]; 0047 int numRects = 4; 0048 0049 if (full) { 0050 rects[0] = qtcRect(x + 4, y + 0, w - 4 * 2, h); 0051 rects[1] = qtcRect(x + 0, y + 4, w, h - 4 * 2); 0052 rects[2] = qtcRect(x + 2, y + 1, w - 2 * 2, h - 2); 0053 rects[3] = qtcRect(x + 1, y + 2, w - 2, h - 2 * 2); 0054 } else { 0055 rects[0] = qtcRect(x + 1, y + 1, w - 2, h - 2); 0056 rects[1] = qtcRect(x, y + 2, w, h - 4); 0057 rects[2] = qtcRect(x + 2, y, w - 4, h); 0058 numRects = 3; 0059 } 0060 return cairo_region_create_rectangles(rects, numRects); 0061 } 0062 #endif 0063 0064 void 0065 drawBgnd(cairo_t *cr, const GdkColor *col, GtkWidget *widget, 0066 const QtcRect *area, int x, int y, int width, int height) 0067 { 0068 Cairo::rect(cr, area, x, y, width, height, 0069 qtcDefault(getParentBgCol(widget), col)); 0070 } 0071 0072 void 0073 drawAreaModColor(cairo_t *cr, const QtcRect *area, const GdkColor *orig, 0074 double mod, int x, int y, int width, int height) 0075 { 0076 const GdkColor modified = shadeColor(orig, mod); 0077 Cairo::rect(cr, area, x, y, width, height, &modified); 0078 } 0079 0080 void 0081 drawBevelGradient(cairo_t *cr, const QtcRect *area, int x, int y, 0082 int width, int height, const GdkColor *base, bool horiz, 0083 bool sel, EAppearance bevApp, EWidget w, double alpha) 0084 { 0085 /* EAppearance app = ((APPEARANCE_BEVELLED != bevApp || widgetIsButton(w) || */ 0086 /* WIDGET_LISTVIEW_HEADER == w) ? bevApp : */ 0087 /* APPEARANCE_GRADIENT); */ 0088 0089 if (qtcIsFlat(bevApp)) { 0090 if (noneOf(w, WIDGET_TAB_TOP, WIDGET_TAB_BOT) || 0091 !qtcIsCustomBgnd(opts) || opts.tabBgnd || !sel) { 0092 Cairo::rect(cr, area, x, y, width, height, base, alpha); 0093 } 0094 } else { 0095 cairo_pattern_t *pt = 0096 cairo_pattern_create_linear(x, y, horiz ? x : x + width - 1, 0097 horiz ? y + height - 1 : y); 0098 bool topTab = w == WIDGET_TAB_TOP; 0099 bool botTab = w == WIDGET_TAB_BOT; 0100 bool selected = (topTab || botTab) ? false : sel; 0101 EAppearance app = (selected ? opts.sunkenAppearance : 0102 WIDGET_LISTVIEW_HEADER == w && 0103 APPEARANCE_BEVELLED == bevApp ? 0104 APPEARANCE_LV_BEVELLED : 0105 APPEARANCE_BEVELLED != bevApp || 0106 widgetIsButton(w) || 0107 WIDGET_LISTVIEW_HEADER == w ? bevApp : 0108 APPEARANCE_GRADIENT); 0109 const Gradient *grad = qtcGetGradient(app, &opts); 0110 Cairo::Saver saver(cr); 0111 Cairo::clipRect(cr, area); 0112 0113 for (int i = 0;i < grad->numStops;i++) { 0114 GdkColor col; 0115 double pos = botTab ? 1.0 - grad->stops[i].pos : grad->stops[i].pos; 0116 0117 if ((topTab || botTab) && i == grad->numStops - 1) { 0118 if (sel && opts.tabBgnd == 0 && !isMozilla()) { 0119 alpha = 0.0; 0120 } 0121 col = *base; 0122 } else { 0123 double val = (botTab && opts.invertBotTab ? 0124 INVERT_SHADE(grad->stops[i].val) : 0125 grad->stops[i].val); 0126 qtcShade(base, &col, botTab && opts.invertBotTab ? 0127 qtcMax(val, 0.9) : val, opts.shading); 0128 } 0129 0130 Cairo::patternAddColorStop(pt, pos, &col, 0131 oneOf(w, WIDGET_TOOLTIP, 0132 WIDGET_LISTVIEW_HEADER) ? 0133 alpha : alpha * grad->stops[i].alpha); 0134 } 0135 0136 if (app == APPEARANCE_AGUA && !(topTab || botTab) && 0137 (horiz ? height : width) > AGUA_MAX) { 0138 GdkColor col; 0139 double pos = AGUA_MAX / ((horiz ? height : width) * 2.0); 0140 0141 qtcShade(base, &col, AGUA_MID_SHADE, opts.shading); 0142 Cairo::patternAddColorStop(pt, pos, &col, alpha); 0143 /* *grad->stops[i].alpha); */ 0144 Cairo::patternAddColorStop(pt, 1.0 - pos, &col, alpha); 0145 /* *grad->stops[i].alpha); */ 0146 } 0147 0148 cairo_set_source(cr, pt); 0149 cairo_rectangle(cr, x, y, width, height); 0150 cairo_fill(cr); 0151 cairo_pattern_destroy(pt); 0152 } 0153 } 0154 0155 void 0156 drawBorder(cairo_t *cr, GtkStyle *style, GtkStateType state, 0157 const QtcRect *area, int x, int y, int width, int height, 0158 const GdkColor *c_colors, ECornerBits round, EBorder borderProfile, 0159 EWidget widget, int flags, int borderVal) 0160 { 0161 if (opts.round == ROUND_NONE && widget != WIDGET_RADIO_BUTTON) { 0162 round = ROUNDED_NONE; 0163 } 0164 double radius = qtcGetRadius(&opts, width, height, widget, RADIUS_EXTERNAL); 0165 double xd = x + 0.5; 0166 double yd = y + 0.5; 0167 /* EAppearance app = qtcWidgetApp(widget, &opts); */ 0168 bool enabled = state != GTK_STATE_INSENSITIVE; 0169 bool useText = (enabled && widget == WIDGET_DEF_BUTTON && 0170 opts.defBtnIndicator == IND_FONT_COLOR); 0171 /* CPD USED TO INDICATE FOCUS! */ 0172 // TODO: what exactly is this 0173 bool hasFocus = (enabled && c_colors == qtcPalette.focus); 0174 bool hasMouseOver = (enabled && qtcPalette.mouseover && 0175 c_colors == qtcPalette.mouseover && 0176 opts.unifyCombo && opts.unifySpin); 0177 const GdkColor *colors = c_colors ? c_colors : qtcPalette.background; 0178 int useBorderVal = (!enabled && widgetIsButton(widget) ? 0179 QTC_STD_BORDER : 0180 qtcPalette.mouseover == colors && IS_SLIDER(widget) ? 0181 SLIDER_MO_BORDER_VAL : borderVal); 0182 const GdkColor *border_col = (useText ? &style->text[GTK_STATE_NORMAL] : 0183 &colors[useBorderVal]); 0184 width--; 0185 height--; 0186 Cairo::Saver saver(cr); 0187 Cairo::clipRect(cr, area); 0188 0189 if (oneOf(widget, WIDGET_TAB_BOT, WIDGET_TAB_TOP)) { 0190 colors = qtcPalette.background; 0191 } 0192 if (!(opts.thin&THIN_FRAMES)) { 0193 switch (borderProfile) { 0194 case BORDER_FLAT: 0195 break; 0196 case BORDER_RAISED: 0197 case BORDER_SUNKEN: 0198 case BORDER_LIGHT: { 0199 double radiusi = qtcGetRadius(&opts, width - 2, height - 2, 0200 widget, RADIUS_INTERNAL); 0201 double xdi = xd + 1; 0202 double ydi = yd + 1; 0203 double alpha = ((hasMouseOver || hasFocus) && 0204 oneOf(widget, WIDGET_ENTRY, WIDGET_SPIN, 0205 WIDGET_COMBO_BUTTON) ? ENTRY_INNER_ALPHA : 0206 BORDER_BLEND_ALPHA(widget)); 0207 int widthi = width - 2; 0208 int heighti = height - 2; 0209 0210 if ((state != GTK_STATE_INSENSITIVE || 0211 borderProfile == BORDER_SUNKEN) /* && */ 0212 /* (oneOf(borderProfile, BORDER_RAISED, BORDER_LIGHT) || */ 0213 /* app != APPEARANCE_FLAT) */) { 0214 const GdkColor *col = 0215 &colors[oneOf(borderProfile, BORDER_RAISED, BORDER_LIGHT) ? 0216 0 : FRAME_DARK_SHADOW]; 0217 if (flags & DF_BLEND) { 0218 if (oneOf(widget, WIDGET_SPIN, WIDGET_COMBO_BUTTON, 0219 WIDGET_SCROLLVIEW)) { 0220 Cairo::setColor(cr, &style->base[state]); 0221 Cairo::pathTopLeft(cr, xdi, ydi, widthi, heighti, 0222 radiusi, round); 0223 cairo_stroke(cr); 0224 } 0225 Cairo::setColor(cr, col, alpha); 0226 } else { 0227 Cairo::setColor(cr, col); 0228 } 0229 } else { 0230 Cairo::setColor(cr, &style->bg[state]); 0231 } 0232 0233 Cairo::pathTopLeft(cr, xdi, ydi, widthi, heighti, radiusi, round); 0234 cairo_stroke(cr); 0235 if (widget != WIDGET_CHECKBOX) { 0236 if(!hasFocus && !hasMouseOver && 0237 borderProfile != BORDER_LIGHT) { 0238 if (widget == WIDGET_SCROLLVIEW) { 0239 /* Because of list view headers, need to draw dark 0240 * line on right! */ 0241 Cairo::Saver saver(cr); 0242 Cairo::setColor(cr, &style->base[state]); 0243 Cairo::pathBottomRight(cr, xdi, ydi, widthi, heighti, 0244 radiusi, round); 0245 cairo_stroke(cr); 0246 } else if (oneOf(widget, WIDGET_SCROLLVIEW, WIDGET_ENTRY)) { 0247 Cairo::setColor(cr, &style->base[state]); 0248 } else if (state != GTK_STATE_INSENSITIVE && 0249 (borderProfile == BORDER_SUNKEN || 0250 /* app != APPEARANCE_FLAT ||*/ 0251 oneOf(widget, WIDGET_TAB_TOP, 0252 WIDGET_TAB_BOT))) { 0253 const GdkColor *col = 0254 &colors[borderProfile == BORDER_RAISED ? 0255 FRAME_DARK_SHADOW : 0]; 0256 if (flags & DF_BLEND) { 0257 Cairo::setColor(cr, col, 0258 borderProfile == BORDER_SUNKEN ? 0259 0.0 : alpha); 0260 } else { 0261 Cairo::setColor(cr, col); 0262 } 0263 } else { 0264 Cairo::setColor(cr, &style->bg[state]); 0265 } 0266 } 0267 0268 Cairo::pathBottomRight(cr, xdi, ydi, widthi, heighti, 0269 radiusi, round); 0270 cairo_stroke(cr); 0271 } 0272 } 0273 } 0274 } 0275 0276 if (borderProfile == BORDER_SUNKEN && 0277 (widget == WIDGET_FRAME || 0278 (oneOf(widget, WIDGET_ENTRY, WIDGET_SCROLLVIEW) && 0279 !opts.etchEntry && !hasFocus && !hasMouseOver))) { 0280 Cairo::setColor(cr, border_col, 0281 /*enabled ? */1.0/* : LOWER_BORDER_ALPHA*/); 0282 Cairo::pathTopLeft(cr, xd, yd, width, height, radius, round); 0283 cairo_stroke(cr); 0284 Cairo::setColor(cr, border_col, LOWER_BORDER_ALPHA); 0285 Cairo::pathBottomRight(cr, xd, yd, width, height, radius, round); 0286 cairo_stroke(cr); 0287 } else { 0288 Cairo::setColor(cr, border_col); 0289 Cairo::pathWhole(cr, xd, yd, width, height, radius, round); 0290 cairo_stroke(cr); 0291 } 0292 } 0293 0294 void 0295 drawGlow(cairo_t *cr, const QtcRect *area, int x, int y, int w, int h, 0296 ECornerBits round, EWidget widget, const GdkColor *colors) 0297 { 0298 if (qtcPalette.mouseover || qtcPalette.defbtn || colors) { 0299 double xd = x + 0.5; 0300 double yd = y + 0.5; 0301 double radius = qtcGetRadius(&opts, w, h, widget, RADIUS_ETCH); 0302 bool def = (widget == WIDGET_DEF_BUTTON && 0303 opts.defBtnIndicator == IND_GLOW); 0304 bool defShade = 0305 (def && (!qtcPalette.defbtn || 0306 (qtcPalette.mouseover && 0307 EQUAL_COLOR(qtcPalette.defbtn[ORIGINAL_SHADE], 0308 qtcPalette.mouseover[ORIGINAL_SHADE])))); 0309 const GdkColor *col = 0310 (colors ? &colors[GLOW_MO] : (def && qtcPalette.defbtn) || 0311 !qtcPalette.mouseover ? &qtcPalette.defbtn[GLOW_DEFBTN] : 0312 &qtcPalette.mouseover[GLOW_MO]); 0313 0314 Cairo::Saver saver(cr); 0315 Cairo::clipRect(cr, area); 0316 Cairo::setColor(cr, col, GLOW_ALPHA(defShade)); 0317 Cairo::pathWhole(cr, xd, yd, w - 1, h - 1, radius, round); 0318 cairo_stroke(cr); 0319 } 0320 } 0321 0322 void 0323 drawEtch(cairo_t *cr, const QtcRect *area, GtkWidget *widget, int x, int y, 0324 int w, int h, bool raised, ECornerBits round, EWidget wid) 0325 { 0326 double xd = x + 0.5; 0327 double yd = y + 0.5; 0328 double radius = qtcGetRadius(&opts, w, h, wid, RADIUS_ETCH); 0329 const QtcRect *a = area; 0330 QtcRect b; 0331 0332 if (wid == WIDGET_TOOLBAR_BUTTON && opts.tbarBtnEffect == EFFECT_ETCH) 0333 raised = false; 0334 0335 if (wid == WIDGET_COMBO_BUTTON && qtSettings.app == GTK_APP_OPEN_OFFICE && 0336 widget && isFixedWidget(gtk_widget_get_parent(widget))) { 0337 b = qtcRect(x + 2, y, w - 4, h); 0338 a = &b; 0339 } 0340 Cairo::Saver saver(cr); 0341 Cairo::clipRect(cr, a); 0342 0343 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0344 USE_CUSTOM_ALPHAS(opts) ? 0345 opts.customAlphas[ALPHA_ETCH_DARK] : ETCH_TOP_ALPHA); 0346 if (!raised && wid != WIDGET_SLIDER) { 0347 Cairo::pathTopLeft(cr, xd, yd, w - 1, h - 1, radius, round); 0348 cairo_stroke(cr); 0349 if (wid == WIDGET_SLIDER_TROUGH && opts.thinSbarGroove && 0350 widget && GTK_IS_SCROLLBAR(widget)) { 0351 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0352 USE_CUSTOM_ALPHAS(opts) ? 0353 opts.customAlphas[ALPHA_ETCH_LIGHT] : 0354 ETCH_BOTTOM_ALPHA); 0355 } else { 0356 setLowerEtchCol(cr, widget); 0357 } 0358 } 0359 Cairo::pathBottomRight(cr, xd, yd, w - 1, h - 1, radius, round); 0360 cairo_stroke(cr); 0361 } 0362 0363 void 0364 qtcClipPath(cairo_t *cr, int x, int y, int w, int h, EWidget widget, 0365 ERadius rad, ECornerBits round) 0366 { 0367 Cairo::clipWhole(cr, x + 0.5, y + 0.5, w - 1, h - 1, 0368 qtcGetRadius(&opts, w, h, widget, rad), round); 0369 } 0370 0371 QTC_ALWAYS_INLINE static inline void 0372 addStripes(cairo_t *cr, int x, int y, int w, int h, bool horizontal) 0373 { 0374 Cairo::stripes(cr, x, y, w, h, horizontal, STRIPE_WIDTH); 0375 } 0376 0377 void 0378 drawLightBevel(cairo_t *cr, GtkStyle *style, GtkStateType state, 0379 const QtcRect *area, int x, int y, int width, int height, 0380 const GdkColor *base, const GdkColor *colors, ECornerBits round, 0381 EWidget widget, EBorder borderProfile, int flags, GtkWidget *wid) 0382 { 0383 EAppearance app = qtcWidgetApp(APPEARANCE_NONE != opts.tbarBtnAppearance && 0384 (WIDGET_TOOLBAR_BUTTON == widget || 0385 (widgetIsButton(widget) && 0386 isOnToolbar(wid, nullptr, 0))) ? 0387 WIDGET_TOOLBAR_BUTTON : widget, &opts); 0388 bool sunken = flags & DF_SUNKEN; 0389 bool doColouredMouseOver = 0390 (opts.coloredMouseOver && qtcPalette.mouseover && 0391 WIDGET_SPIN != widget && WIDGET_SPIN_DOWN != widget && 0392 WIDGET_SPIN_UP != widget && WIDGET_COMBO_BUTTON != widget && 0393 WIDGET_SB_BUTTON != widget && (!SLIDER(widget) || 0394 !opts.colorSliderMouseOver) && 0395 WIDGET_UNCOLOURED_MO_BUTTON != widget && GTK_STATE_PRELIGHT == state && 0396 (!sunken || IS_TOGGLE_BUTTON(widget) || 0397 (WIDGET_TOOLBAR_BUTTON == widget && opts.coloredTbarMo))); 0398 bool plastikMouseOver = (doColouredMouseOver && 0399 opts.coloredMouseOver == MO_PLASTIK); 0400 bool colouredMouseOver = 0401 (doColouredMouseOver && oneOf(opts.coloredMouseOver, MO_COLORED, 0402 MO_COLORED_THICK)); 0403 bool flatWidget = (widget == WIDGET_PROGRESSBAR && !opts.borderProgress); 0404 bool lightBorder = !flatWidget && DRAW_LIGHT_BORDER(sunken, widget, app); 0405 bool draw3dfull = (!flatWidget && !lightBorder && 0406 DRAW_3D_FULL_BORDER(sunken, app)); 0407 bool draw3d = 0408 (!flatWidget && (draw3dfull || 0409 (!lightBorder && DRAW_3D_BORDER(sunken, app)))); 0410 bool drawShine = DRAW_SHINE(sunken, app); 0411 bool bevelledButton = widgetIsButton(widget) && app == APPEARANCE_BEVELLED; 0412 bool doEtch = 0413 (flags & DF_DO_BORDER && 0414 (ETCH_WIDGET(widget) || (WIDGET_COMBO_BUTTON == widget && 0415 opts.etchEntry)) && 0416 opts.buttonEffect != EFFECT_NONE); 0417 bool glowFocus = 0418 (doEtch && USE_GLOW_FOCUS(GTK_STATE_PRELIGHT == state) && wid && 0419 ((flags&DF_HAS_FOCUS) || gtk_widget_has_focus(wid)) && 0420 GTK_STATE_INSENSITIVE != state && !isComboBoxEntryButton(wid) && 0421 ((WIDGET_RADIO_BUTTON != widget && WIDGET_CHECKBOX != widget) || 0422 GTK_STATE_ACTIVE != state)); 0423 bool glowFocusSunkenToggle = 0424 (sunken && (glowFocus || (doColouredMouseOver && 0425 MO_GLOW == opts.coloredMouseOver)) && 0426 wid && GTK_IS_TOGGLE_BUTTON(wid)); 0427 bool horiz = !(flags & DF_VERT); 0428 int xe = x, ye = y; 0429 int we = width, he = height; 0430 int origWidth = width, origHeight = height; 0431 double xd = x + 0.5, yd = y + 0.5; 0432 if (CIRCULAR_SLIDER(widget)) 0433 horiz = true; 0434 0435 if (WIDGET_TROUGH == widget && !opts.borderSbarGroove && 0436 flags & DF_DO_BORDER) { 0437 flags -= DF_DO_BORDER; 0438 } 0439 0440 if (WIDGET_COMBO_BUTTON == widget && doEtch) { 0441 if (ROUNDED_RIGHT == round) { 0442 x--; 0443 xd -= 1; 0444 width++; 0445 } else if(ROUNDED_LEFT == round) { 0446 width++; 0447 } 0448 } 0449 0450 if (doEtch) { 0451 xd += 1; 0452 x++; 0453 yd += 1; 0454 y++; 0455 width -= 2; 0456 height -= 2; 0457 xe = x; 0458 ye = y; 0459 we = width; 0460 he = height; 0461 } 0462 0463 if (width > 0 && height > 0) { 0464 Cairo::Saver saver(cr); 0465 if (!(flags & DF_DO_BORDER)) { 0466 Cairo::clipWhole(cr, x, y, width, height, 0467 qtcGetRadius(&opts, width, height, widget, 0468 RADIUS_EXTERNAL), round); 0469 } else { 0470 qtcClipPath(cr, x, y, width, height, widget, 0471 RADIUS_EXTERNAL, round); 0472 } 0473 drawBevelGradient(cr, area, x, y, width, height, base, horiz, 0474 sunken && !IS_TROUGH(widget), app, widget); 0475 if (plastikMouseOver) { 0476 if (SLIDER(widget)) { 0477 int len = sbSliderMOLen(opts, horiz ? width : height); 0478 int so = lightBorder ? SLIDER_MO_PLASTIK_BORDER : 1; 0479 int eo = len + so; 0480 int col = SLIDER_MO_SHADE; 0481 0482 if (horiz) { 0483 drawBevelGradient(cr, area, x + so, y, len, height, 0484 &qtcPalette.mouseover[col], horiz, 0485 sunken, app, widget); 0486 drawBevelGradient(cr, area, x + width - eo, y, len, 0487 height, &qtcPalette.mouseover[col], 0488 horiz, sunken, app, widget); 0489 } else { 0490 drawBevelGradient(cr, area, x, y + so, width, len, 0491 &qtcPalette.mouseover[col], horiz, 0492 sunken, app, widget); 0493 drawBevelGradient(cr, area, x, y + height - eo, 0494 width, len, &qtcPalette.mouseover[col], 0495 horiz, sunken, app, widget); 0496 } 0497 } else { 0498 int mh = height; 0499 const GdkColor *col = 0500 &qtcPalette.mouseover[MO_PLASTIK_DARK(widget)]; 0501 bool horizontal = 0502 ((horiz && !(WIDGET_SB_BUTTON == widget || 0503 SLIDER(widget))) || 0504 (!horiz && (WIDGET_SB_BUTTON == widget || 0505 SLIDER(widget)))); 0506 bool thin = 0507 (oneOf(widget, WIDGET_SB_BUTTON, WIDGET_SPIN_UP, 0508 WIDGET_SPIN_DOWN) || 0509 (horiz ? height : width) < 16); 0510 0511 if (EFFECT_NONE != opts.buttonEffect && 0512 WIDGET_SPIN_UP == widget && horiz) { 0513 mh--; 0514 } 0515 cairo_new_path(cr); 0516 Cairo::setColor(cr, col); 0517 if (horizontal) { 0518 cairo_move_to(cr, x + 1, yd + 1); 0519 cairo_line_to(cr, x + width -1, yd + 1); 0520 cairo_move_to(cr, x + 1, yd + mh - 2); 0521 cairo_line_to(cr, x + width - 1, yd + mh - 2); 0522 } else { 0523 cairo_move_to(cr, xd + 1, y + 1); 0524 cairo_line_to(cr, xd + 1, y + mh - 1); 0525 cairo_move_to(cr, xd + width - 2, y + 1); 0526 cairo_line_to(cr, xd + width - 2, y + mh - 1); 0527 } 0528 cairo_stroke(cr); 0529 if (!thin) { 0530 col = &qtcPalette.mouseover[MO_PLASTIK_LIGHT(widget)]; 0531 cairo_new_path(cr); 0532 Cairo::setColor(cr, col); 0533 if (horizontal) { 0534 cairo_move_to(cr, x + 1, yd + 2); 0535 cairo_line_to(cr, x + width - 1, yd + 2); 0536 cairo_move_to(cr, x + 1, yd + mh - 3); 0537 cairo_line_to(cr, x + width - 1, yd + mh - 3); 0538 } else { 0539 cairo_move_to(cr, xd + 2, y + 1); 0540 cairo_line_to(cr, xd + 2, y + mh - 1); 0541 cairo_move_to(cr, xd + width - 3, y + 1); 0542 cairo_line_to(cr, xd + width - 3, y + mh - 1); 0543 } 0544 cairo_stroke(cr); 0545 } 0546 } 0547 } 0548 0549 if (drawShine) { 0550 bool mo = state == GTK_STATE_PRELIGHT && opts.highlightFactor; 0551 int xa = x; 0552 int ya = y; 0553 int wa = width; 0554 int ha = height; 0555 if (widget == WIDGET_RADIO_BUTTON || CIRCULAR_SLIDER(widget)) { 0556 double topSize = ha * 0.4; 0557 double topWidthAdjust = 3.5; 0558 double topGradRectX = xa + topWidthAdjust; 0559 double topGradRectY = ya; 0560 double topGradRectW = wa - topWidthAdjust * 2 - 1; 0561 double topGradRectH = topSize - 1; 0562 cairo_pattern_t *pt = 0563 cairo_pattern_create_linear(topGradRectX, topGradRectY, 0564 topGradRectX, 0565 topGradRectY + topGradRectH); 0566 0567 Cairo::Saver saver(cr); 0568 Cairo::clipWhole(cr, topGradRectX + 0.5, topGradRectY + 0.5, 0569 topGradRectW, topGradRectH, 0570 topGradRectW / 2.0, ROUNDED_ALL); 0571 0572 cairo_pattern_add_color_stop_rgba( 0573 pt, 0.0, 1.0, 1.0, 1.0, 0574 mo ? (opts.highlightFactor > 0 ? 0.8 : 0.7) : 0.75); 0575 cairo_pattern_add_color_stop_rgba( 0576 pt, CAIRO_GRAD_END, 1.0, 1.0, 1.0, 0577 /*mo ? (opts.highlightFactor>0 ? 0.3 : 0.1) :*/ 0.2); 0578 0579 cairo_set_source(cr, pt); 0580 cairo_rectangle(cr, topGradRectX, topGradRectY, topGradRectW, 0581 topGradRectH); 0582 cairo_fill(cr); 0583 cairo_pattern_destroy(pt); 0584 } else { 0585 double size = qtcMin((horiz ? ha : wa) / 2.0, 16); 0586 double rad = size / 2.0; 0587 cairo_pattern_t *pt = nullptr; 0588 int mod = 4; 0589 0590 if (horiz) { 0591 if (!(ROUNDED_LEFT & round)) { 0592 xa -= 8; 0593 wa += 8; 0594 } 0595 if (!(ROUNDED_RIGHT & round)) { 0596 wa += 8; 0597 } 0598 } else { 0599 if (!(ROUNDED_TOP & round)) { 0600 ya -= 8; 0601 ha += 8; 0602 } 0603 if (!(ROUNDED_BOTTOM & round)) { 0604 ha += 8; 0605 } 0606 } 0607 pt = cairo_pattern_create_linear( 0608 xa, ya, xa + (horiz ? 0.0 : size), 0609 ya + (horiz ? size : 0.0)); 0610 0611 if (qtcGetWidgetRound(&opts, origWidth, origHeight, 0612 widget) < ROUND_MAX || 0613 (!isMaxRoundWidget(widget) && !IS_SLIDER(widget))) { 0614 rad /= 2.0; 0615 mod /= 2; 0616 } 0617 0618 Cairo::Saver saver(cr); 0619 if (horiz) { 0620 Cairo::clipWhole(cr, xa + mod + 0.5, ya + 0.5, 0621 wa - mod * 2 - 1, size - 1, rad, round); 0622 } else { 0623 Cairo::clipWhole(cr, xa + 0.5, ya + mod + 0.5, size - 1, 0624 ha - mod * 2 - 1, rad, round); 0625 } 0626 0627 cairo_pattern_add_color_stop_rgba( 0628 pt, 0.0, 1.0, 1.0, 1.0, 0629 mo ? (opts.highlightFactor > 0 ? 0.95 : 0.85) : 0.9); 0630 cairo_pattern_add_color_stop_rgba( 0631 pt, CAIRO_GRAD_END, 1.0, 1.0, 1.0, 0632 mo ? (opts.highlightFactor > 0 ? 0.3 : 0.1) : 0.2); 0633 0634 cairo_set_source(cr, pt); 0635 cairo_rectangle(cr, xa, ya, horiz ? wa : size, 0636 horiz ? size : ha); 0637 cairo_fill(cr); 0638 cairo_pattern_destroy(pt); 0639 } 0640 } 0641 } 0642 xd += 1; 0643 x++; 0644 yd += 1; 0645 y++; 0646 width -= 2; 0647 height -= 2; 0648 0649 cairo_save(cr); 0650 if (plastikMouseOver /* && !sunken */) { 0651 bool thin = (oneOf(widget, WIDGET_SB_BUTTON, WIDGET_SPIN) || 0652 (horiz ? height : width) < 16); 0653 bool horizontal = 0654 (SLIDER(widget) ? !horiz : (horiz && WIDGET_SB_BUTTON != widget) || 0655 (!horiz && WIDGET_SB_BUTTON == widget)); 0656 int len = (SLIDER(widget) ? 0657 sbSliderMOLen(opts, horiz ? width : height) : 0658 (thin ? 1 : 2)); 0659 QtcRect rect; 0660 if (horizontal) { 0661 rect = qtcRect(x, y + len, width, height - len * 2); 0662 } else { 0663 rect = qtcRect(x + len, y, width - len * 2, height); 0664 } 0665 Cairo::clipRect(cr, &rect); 0666 } else { 0667 Cairo::clipRect(cr, area); 0668 } 0669 0670 if (!colouredMouseOver && lightBorder) { 0671 const GdkColor *col = &colors[LIGHT_BORDER(app)]; 0672 0673 cairo_new_path(cr); 0674 Cairo::setColor(cr, col); 0675 Cairo::pathWhole(cr, xd, yd, width - 1, height - 1, 0676 qtcGetRadius(&opts, width, height, widget, 0677 RADIUS_INTERNAL), round); 0678 cairo_stroke(cr); 0679 } else if (colouredMouseOver || 0680 (!sunken && (draw3d || flags & DF_DRAW_INSIDE))) { 0681 int dark = /*bevelledButton ? */2/* : 4*/; 0682 const GdkColor *col1 = 0683 (colouredMouseOver ? 0684 &qtcPalette.mouseover[MO_STD_LIGHT(widget, sunken)] : 0685 &colors[sunken ? dark : 0]); 0686 0687 cairo_new_path(cr); 0688 Cairo::setColor(cr, col1); 0689 Cairo::pathTopLeft(cr, xd, yd, width - 1, height - 1, 0690 qtcGetRadius(&opts, width, height, widget, 0691 RADIUS_INTERNAL), round); 0692 cairo_stroke(cr); 0693 if (colouredMouseOver || bevelledButton || draw3dfull) { 0694 const GdkColor *col2 = colouredMouseOver ? 0695 &qtcPalette.mouseover[MO_STD_DARK(widget)] : 0696 &colors[sunken ? 0 : dark]; 0697 0698 cairo_new_path(cr); 0699 Cairo::setColor(cr, col2); 0700 Cairo::pathBottomRight(cr, xd, yd, width - 1, height - 1, 0701 qtcGetRadius(&opts, width, height, widget, 0702 RADIUS_INTERNAL), round); 0703 cairo_stroke(cr); 0704 } 0705 } 0706 0707 cairo_restore(cr); 0708 0709 if ((doEtch || glowFocus) && !(flags & DF_HIDE_EFFECT)) { 0710 if ((!sunken || glowFocusSunkenToggle) && 0711 GTK_STATE_INSENSITIVE != state && !(opts.thin&THIN_FRAMES) && 0712 ((noneOf(widget, WIDGET_OTHER, WIDGET_SLIDER_TROUGH, 0713 WIDGET_COMBO_BUTTON) && 0714 opts.coloredMouseOver == MO_GLOW && 0715 state == GTK_STATE_PRELIGHT) || glowFocus || 0716 (widget == WIDGET_DEF_BUTTON && 0717 opts.defBtnIndicator == IND_GLOW))) { 0718 drawGlow(cr, area, xe - 1, ye - 1, we + 2, he + 2, round, 0719 (widget == WIDGET_DEF_BUTTON && 0720 state == GTK_STATE_PRELIGHT ? WIDGET_STD_BUTTON : widget), 0721 glowFocus ? qtcPalette.focus : nullptr); 0722 } else { 0723 drawEtch(cr, area, wid, 0724 xe - (WIDGET_COMBO_BUTTON == widget ? 0725 (ROUNDED_RIGHT==round ? 3 : 1) : 1), ye - 1, 0726 we + (WIDGET_COMBO_BUTTON == widget ? 0727 (ROUNDED_RIGHT == round ? 4 : 5) : 2), he + 2, 0728 EFFECT_SHADOW == opts.buttonEffect && 0729 WIDGET_COMBO_BUTTON != widget && widgetIsButton(widget) && 0730 !sunken, round, widget); 0731 } 0732 } 0733 0734 xd -= 1; 0735 x--; 0736 yd -= 1; 0737 y--; 0738 width += 2; 0739 height += 2; 0740 if (flags & DF_DO_BORDER && width > 2 && height > 2) { 0741 const GdkColor *borderCols = 0742 (glowFocus && (!sunken || glowFocusSunkenToggle) ? 0743 qtcPalette.focus : oneOf(widget, WIDGET_COMBO, 0744 WIDGET_COMBO_BUTTON) && 0745 qtcPalette.combobtn == colors ? 0746 state == GTK_STATE_PRELIGHT && opts.coloredMouseOver == MO_GLOW && 0747 !sunken ? qtcPalette.mouseover : 0748 qtcPalette.button[PAL_ACTIVE] : colors); 0749 0750 cairo_new_path(cr); 0751 /* Yuck! this is a mess!!!! */ 0752 // Copied from KDE4 version... 0753 if (!sunken && state != GTK_STATE_INSENSITIVE && !glowFocus && 0754 ((((doEtch && noneOf(widget, WIDGET_OTHER, 0755 WIDGET_SLIDER_TROUGH)) || SLIDER(widget) || 0756 oneOf(widget, WIDGET_COMBO, WIDGET_MENU_BUTTON)) && 0757 (opts.coloredMouseOver == MO_GLOW 0758 /* || opts.colorMenubarMouseOver == MO_COLORED */) && 0759 state == GTK_STATE_PRELIGHT) || 0760 (doEtch && widget == WIDGET_DEF_BUTTON && 0761 opts.defBtnIndicator == IND_GLOW))) { 0762 0763 // Previous Gtk2... 0764 // if(!sunken && (doEtch || SLIDER(widget)) && 0765 // ( (WIDGET_OTHER!=widget && WIDGET_SLIDER_TROUGH!=widget && WIDGET_COMBO_BUTTON!=widget && 0766 // MO_GLOW==opts.coloredMouseOver && GTK_STATE_PRELIGHT==state) || 0767 // (WIDGET_DEF_BUTTON==widget && IND_GLOW==opts.defBtnIndicator))) 0768 drawBorder(cr, style, state, area, x, y, width, height, 0769 widget == WIDGET_DEF_BUTTON && 0770 opts.defBtnIndicator == IND_GLOW && 0771 (state != GTK_STATE_PRELIGHT || !qtcPalette.mouseover) ? 0772 qtcPalette.defbtn : qtcPalette.mouseover, 0773 round, borderProfile, widget, flags); 0774 } else { 0775 drawBorder(cr, style, state, area, x, y, width, height, 0776 colouredMouseOver && 0777 opts.coloredMouseOver == MO_COLORED_THICK ? 0778 qtcPalette.mouseover : borderCols, 0779 round, borderProfile, widget, flags); 0780 } 0781 } 0782 0783 if (WIDGET_SB_SLIDER == widget && opts.stripedSbar) { 0784 Cairo::Saver saver(cr); 0785 Cairo::clipWhole(cr, x, y, width, height, 0786 qtcGetRadius(&opts, width, height, WIDGET_SB_SLIDER, 0787 RADIUS_INTERNAL), round); 0788 addStripes(cr, x + 1, y + 1, width - 2, height - 2, horiz); 0789 } 0790 } 0791 0792 void 0793 drawFadedLine(cairo_t *cr, int x, int y, int width, int height, 0794 const GdkColor *col, const QtcRect *area, const QtcRect *gap, 0795 bool fadeStart, bool fadeEnd, bool horiz, double alpha) 0796 { 0797 Cairo::fadedLine(cr, x, y, width, height, area, gap, 0798 fadeStart && opts.fadeLines, 0799 fadeEnd && opts.fadeLines, FADE_SIZE, horiz, col, alpha); 0800 } 0801 0802 void 0803 drawHighlight(cairo_t *cr, int x, int y, int width, int height, 0804 const QtcRect *area, bool horiz, bool inc) 0805 { 0806 drawFadedLine(cr, x, y, width, height, 0807 &qtcPalette.mouseover[ORIGINAL_SHADE], area, nullptr, 0808 true, true, horiz, inc ? 0.5 : 1.0); 0809 drawFadedLine(cr, x + (horiz ? 0 : 1), y + (horiz ? 1 : 0), width, height, 0810 &qtcPalette.mouseover[ORIGINAL_SHADE], area, nullptr, 0811 true, true, horiz, inc ? 1.0 : 0.5); 0812 } 0813 0814 void setLineCol(cairo_t *cr, cairo_pattern_t *pt, const GdkColor *col) 0815 { 0816 if (pt) { 0817 Cairo::patternAddColorStop(pt, 0, col, 0.0); 0818 Cairo::patternAddColorStop(pt, 0.4, col); 0819 Cairo::patternAddColorStop(pt, 0.6, col); 0820 Cairo::patternAddColorStop(pt, CAIRO_GRAD_END, col, 0.0); 0821 cairo_set_source(cr, pt); 0822 } else { 0823 Cairo::setColor(cr, col); 0824 } 0825 } 0826 0827 void 0828 drawLines(cairo_t *cr, double rx, double ry, int rwidth, int rheight, 0829 bool horiz, int nLines, int offset, const GdkColor *cols, 0830 const QtcRect *area, int dark, ELine type) 0831 { 0832 if (horiz) { 0833 ry += 0.5; 0834 rwidth += 1; 0835 } else { 0836 rx += 0.5; 0837 rheight += 1; 0838 } 0839 int space = nLines * 2 + (type != LINE_DASHES ? nLines - 1 : 0); 0840 int step = type != LINE_DASHES ? 3 : 2; 0841 int etchedDisp = type == LINE_SUNKEN ? 1 : 0; 0842 double x = horiz ? rx : rx + (rwidth - space) / 2; 0843 double y = horiz ? ry + (rheight - space) / 2 : ry; 0844 double x2 = rx + rwidth - 1; 0845 double y2 = ry + rheight - 1; 0846 const GdkColor *col1 = &cols[dark]; 0847 const GdkColor *col2 = &cols[0]; 0848 cairo_pattern_t *pt1 = 0849 ((opts.fadeLines && (horiz ? rwidth : rheight) > (16 + etchedDisp)) ? 0850 cairo_pattern_create_linear(rx, ry, horiz ? x2 : rx + 1, 0851 horiz ? ry + 1 : y2) : nullptr); 0852 cairo_pattern_t *pt2 = 0853 ((pt1 && type != LINE_FLAT) ? 0854 cairo_pattern_create_linear(rx, ry, horiz ? x2 : rx + 1, 0855 horiz ? ry + 1 : y2) : nullptr); 0856 Cairo::Saver saver(cr); 0857 Cairo::clipRect(cr, area); 0858 setLineCol(cr, pt1, col1); 0859 if (horiz) { 0860 for (int i = 0;i < space;i += step) { 0861 cairo_move_to(cr, x + offset, y + i); 0862 cairo_line_to(cr, x2 - offset, y + i); 0863 } 0864 cairo_stroke(cr); 0865 if (type != LINE_FLAT) { 0866 setLineCol(cr, pt2, col2); 0867 x += etchedDisp; 0868 x2 += etchedDisp; 0869 for (int i = 1;i < space;i += step) { 0870 cairo_move_to(cr, x + offset, y + i); 0871 cairo_line_to(cr, x2 - offset, y + i); 0872 } 0873 cairo_stroke(cr); 0874 } 0875 } else { 0876 for (int i = 0;i < space;i += step) { 0877 cairo_move_to(cr, x + i, y + offset); 0878 cairo_line_to(cr, x + i, y2 - offset); 0879 } 0880 cairo_stroke(cr); 0881 if (type != LINE_FLAT) { 0882 setLineCol(cr, pt2, col2); 0883 y += etchedDisp; 0884 y2 += etchedDisp; 0885 for (int i = 1;i < space;i += step) { 0886 cairo_move_to(cr, x + i, y + offset); 0887 cairo_line_to(cr, x + i, y2 - offset); 0888 } 0889 cairo_stroke(cr); 0890 } 0891 } 0892 if (pt1) { 0893 cairo_pattern_destroy(pt1); 0894 } 0895 if (pt2) { 0896 cairo_pattern_destroy(pt2); 0897 } 0898 } 0899 0900 void 0901 drawEntryCorners(cairo_t *cr, const QtcRect *area, int round, int x, int y, 0902 int width, int height, const GdkColor *col, double a) 0903 { 0904 Cairo::Saver saver(cr); 0905 Cairo::clipRect(cr, area); 0906 Cairo::setColor(cr, col, a); 0907 cairo_rectangle(cr, x + 0.5, y + 0.5, width - 1, height - 1); 0908 if (opts.buttonEffect != EFFECT_NONE && opts.etchEntry) { 0909 cairo_rectangle(cr, x + 1.5, y + 1.5, width - 2, height - 3); 0910 } 0911 if (opts.round > ROUND_FULL) { 0912 if (round & CORNER_TL) { 0913 cairo_rectangle(cr, x + 2.5, y + 2.5, 1, 1); 0914 } 0915 if (round & CORNER_BL) { 0916 cairo_rectangle(cr, x + 2.5, y + height - 3.5, 1, 1); 0917 } 0918 if (round & CORNER_TR) { 0919 cairo_rectangle(cr, x + width - 2.5, y + 2.5, 1, 1); 0920 } 0921 if (round & CORNER_BR) { 0922 cairo_rectangle(cr, x + width - 2.5, y + height - 3.5, 1, 1); 0923 } 0924 } 0925 cairo_set_line_width(cr, opts.round > ROUND_FULL && 0926 qtSettings.app != GTK_APP_OPEN_OFFICE ? 2 : 1); 0927 cairo_stroke(cr); 0928 } 0929 0930 void 0931 drawBgndRing(cairo_t *cr, int x, int y, int size, int size2, bool isWindow) 0932 { 0933 double width = (size - size2) / 2.0; 0934 double width2 = width / 2.0; 0935 double radius = (size2 + width) / 2.0; 0936 0937 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0938 RINGS_INNER_ALPHA(isWindow ? opts.bgndImage.type : 0939 opts.menuBgndImage.type)); 0940 cairo_set_line_width(cr, width); 0941 cairo_arc(cr, x + radius + width2 + 0.5, y + radius + width2 + 0.5, radius, 0942 0, 2 * M_PI); 0943 cairo_stroke(cr); 0944 0945 if ((isWindow ? opts.bgndImage.type : 0946 opts.menuBgndImage.type) == IMG_BORDERED_RINGS) { 0947 cairo_set_line_width(cr, 1); 0948 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, RINGS_OUTER_ALPHA); 0949 cairo_arc(cr, x + radius + width2 + 0.5, y + radius + width2 + 0.5, 0950 size / 2.0, 0, 2 * M_PI); 0951 if (size2) { 0952 cairo_stroke(cr); 0953 cairo_arc(cr, x + radius + width2 + 0.5, y + radius + width2 + 0.5, 0954 size2 / 2.0, 0, 2 * M_PI); 0955 } 0956 cairo_stroke(cr); 0957 } 0958 } 0959 0960 void 0961 drawBgndRings(cairo_t *cr, int x, int y, int width, int height, bool isWindow) 0962 { 0963 static cairo_surface_t *bgndImage = nullptr; 0964 static cairo_surface_t *menuBgndImage = nullptr; 0965 0966 bool useWindow = (isWindow || 0967 (opts.bgndImage.type == opts.menuBgndImage.type && 0968 (opts.bgndImage.type != IMG_FILE || 0969 (opts.bgndImage.height == opts.menuBgndImage.height && 0970 opts.bgndImage.width == opts.menuBgndImage.width && 0971 opts.bgndImage.pixmap.file == 0972 opts.menuBgndImage.pixmap.file)))); 0973 QtCImage *img = useWindow ? &opts.bgndImage : &opts.menuBgndImage; 0974 int imgWidth = img->type == IMG_FILE ? img->width : RINGS_WIDTH(img->type); 0975 int imgHeight = (img->type == IMG_FILE ? img->height : 0976 RINGS_HEIGHT(img->type)); 0977 0978 switch (img->type) { 0979 case IMG_NONE: 0980 break; 0981 case IMG_FILE: 0982 qtcLoadBgndImage(img); 0983 if (img->pixmap.img) { 0984 switch (img->pos) { 0985 case PP_TL: 0986 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, x, y); 0987 break; 0988 case PP_TM: 0989 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, 0990 x + (width - img->width) / 2, y); 0991 break; 0992 default: 0993 case PP_TR: 0994 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, 0995 x + width - img->width - 1, y); 0996 break; 0997 case PP_BL: 0998 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, x, 0999 y + height - img->height); 1000 break; 1001 case PP_BM: 1002 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, 1003 x + (width - img->width) / 2, 1004 y + height - img->height - 1); 1005 break; 1006 case PP_BR: 1007 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, 1008 x + width - img->width - 1, 1009 y + height - img->height - 1); 1010 break; 1011 case PP_LM: 1012 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, x, 1013 y + (height - img->height) / 2); 1014 break; 1015 case PP_RM: 1016 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, 1017 x + width - img->width - 1, 1018 y + (height - img->height) / 2); 1019 break; 1020 case PP_CENTRED: 1021 gdk_cairo_set_source_pixbuf(cr, img->pixmap.img, 1022 x + (width - img->width) / 2, 1023 y + (height - img->height) / 2); 1024 } 1025 cairo_paint(cr); 1026 } 1027 break; 1028 case IMG_PLAIN_RINGS: 1029 case IMG_BORDERED_RINGS: { 1030 cairo_surface_t *crImg = useWindow ? bgndImage : menuBgndImage; 1031 1032 if (!crImg) { 1033 cairo_t *ci; 1034 crImg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1035 imgWidth + 1, imgHeight + 1); 1036 ci = cairo_create(crImg); 1037 drawBgndRing(ci, 0, 0, 200, 140, isWindow); 1038 1039 drawBgndRing(ci, 210, 10, 230, 214, isWindow); 1040 drawBgndRing(ci, 226, 26, 198, 182, isWindow); 1041 drawBgndRing(ci, 300, 100, 50, 0, isWindow); 1042 1043 drawBgndRing(ci, 100, 96, 160, 144, isWindow); 1044 drawBgndRing(ci, 116, 112, 128, 112, isWindow); 1045 1046 drawBgndRing(ci, 250, 160, 200, 140, isWindow); 1047 drawBgndRing(ci, 310, 220, 80, 0, isWindow); 1048 cairo_destroy(ci); 1049 if (useWindow) { 1050 bgndImage = crImg; 1051 } else { 1052 menuBgndImage = crImg; 1053 } 1054 } 1055 1056 cairo_set_source_surface(cr, crImg, width - imgWidth, y + 1); 1057 cairo_paint(cr); 1058 break; 1059 } 1060 case IMG_SQUARE_RINGS: { 1061 cairo_surface_t *crImg = useWindow ? bgndImage : menuBgndImage; 1062 1063 if (!crImg) { 1064 double halfWidth = RINGS_SQUARE_LINE_WIDTH / 2.0; 1065 crImg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1066 imgWidth + 1, imgHeight + 1); 1067 cairo_t *ci = cairo_create(crImg); 1068 1069 cairo_set_source_rgba(ci, 1.0, 1.0, 1.0, RINGS_SQUARE_SMALL_ALPHA); 1070 cairo_set_line_width(ci, RINGS_SQUARE_LINE_WIDTH); 1071 Cairo::pathWhole(ci, halfWidth + 0.5, halfWidth + 0.5, 1072 RINGS_SQUARE_SMALL_SIZE, RINGS_SQUARE_SMALL_SIZE, 1073 RINGS_SQUARE_RADIUS, ROUNDED_ALL); 1074 cairo_stroke(ci); 1075 1076 cairo_new_path(ci); 1077 cairo_set_source_rgba(ci, 1.0, 1.0, 1.0, RINGS_SQUARE_SMALL_ALPHA); 1078 cairo_set_line_width(ci, RINGS_SQUARE_LINE_WIDTH); 1079 Cairo::pathWhole(ci, halfWidth + 0.5 + imgWidth - 1080 RINGS_SQUARE_SMALL_SIZE - RINGS_SQUARE_LINE_WIDTH, 1081 halfWidth + 0.5 + imgHeight - 1082 RINGS_SQUARE_SMALL_SIZE - RINGS_SQUARE_LINE_WIDTH, 1083 RINGS_SQUARE_SMALL_SIZE, RINGS_SQUARE_SMALL_SIZE, 1084 RINGS_SQUARE_RADIUS, ROUNDED_ALL); 1085 cairo_stroke(ci); 1086 1087 cairo_new_path(ci); 1088 cairo_set_source_rgba(ci, 1.0, 1.0, 1.0, RINGS_SQUARE_LARGE_ALPHA); 1089 cairo_set_line_width(ci, RINGS_SQUARE_LINE_WIDTH); 1090 Cairo::pathWhole(ci, halfWidth + 0.5 + 1091 (imgWidth - RINGS_SQUARE_LARGE_SIZE - 1092 RINGS_SQUARE_LINE_WIDTH) / 2.0, 1093 halfWidth + 0.5 + 1094 (imgHeight - RINGS_SQUARE_LARGE_SIZE - 1095 RINGS_SQUARE_LINE_WIDTH) / 2.0, 1096 RINGS_SQUARE_LARGE_SIZE, RINGS_SQUARE_LARGE_SIZE, 1097 RINGS_SQUARE_RADIUS, ROUNDED_ALL); 1098 cairo_stroke(ci); 1099 1100 cairo_destroy(ci); 1101 1102 if (useWindow) { 1103 bgndImage = crImg; 1104 } else { 1105 menuBgndImage = crImg; 1106 } 1107 } 1108 1109 cairo_set_source_surface(cr, crImg, width-imgWidth, y+1); 1110 cairo_paint(cr); 1111 break; 1112 } 1113 } 1114 } 1115 1116 void 1117 drawBgndImage(cairo_t *cr, int x, int y, int w, int h, bool isWindow) 1118 { 1119 GdkPixbuf *pix = isWindow ? opts.bgndPixmap.img : opts.menuBgndPixmap.img; 1120 if (pix) { 1121 gdk_cairo_set_source_pixbuf(cr, pix, 0, 0); 1122 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); 1123 cairo_rectangle(cr, x, y, w, h); 1124 cairo_fill(cr); 1125 } 1126 } 1127 1128 void 1129 drawStripedBgnd(cairo_t *cr, int x, int y, int w, int h, 1130 const GdkColor *col, double alpha) 1131 { 1132 GdkColor col2; 1133 qtcShade(col, &col2, BGND_STRIPE_SHADE, opts.shading); 1134 1135 cairo_pattern_t *pat = cairo_pattern_create_linear(x, y, x, y + 4); 1136 Cairo::patternAddColorStop(pat, 0.0, col, alpha); 1137 Cairo::patternAddColorStop(pat, 0.25 - 0.0001, col, alpha); 1138 Cairo::patternAddColorStop(pat, 0.5, &col2, alpha); 1139 Cairo::patternAddColorStop(pat, 0.75 - 0.0001, &col2, alpha); 1140 col2.red = (3 * col->red + col2.red) / 4; 1141 col2.green = (3 * col->green + col2.green) / 4; 1142 col2.blue = (3 * col->blue + col2.blue) / 4; 1143 Cairo::patternAddColorStop(pat, 0.25, &col2, alpha); 1144 Cairo::patternAddColorStop(pat, 0.5 - 0.0001, &col2, alpha); 1145 Cairo::patternAddColorStop(pat, 0.75, &col2, alpha); 1146 Cairo::patternAddColorStop(pat, CAIRO_GRAD_END, &col2, alpha); 1147 1148 cairo_pattern_set_extend(pat, CAIRO_EXTEND_REPEAT); 1149 cairo_set_source(cr, pat); 1150 cairo_rectangle(cr, x, y, w, h); 1151 cairo_fill(cr); 1152 cairo_pattern_destroy(pat); 1153 } 1154 1155 bool 1156 drawWindowBgnd(cairo_t *cr, GtkStyle *style, const QtcRect *area, 1157 GdkWindow *window, GtkWidget *widget, int x, int y, 1158 int width, int height) 1159 { 1160 GtkWidget *parent = nullptr; 1161 if (widget && (parent = gtk_widget_get_parent(widget)) && 1162 isOnHandlebox(parent, nullptr, 0)) { 1163 return true; 1164 } 1165 if (!isFixedWidget(widget) && !isGimpDockable(widget)) { 1166 int wx = 0; 1167 int wy = 0; 1168 int wh = 0; 1169 int ww = 0; 1170 1171 if (!mapToTopLevel(window, widget, &wx, &wy, &ww, &wh)) { 1172 return false; 1173 } 1174 GtkWidget *topLevel = gtk_widget_get_toplevel(widget); 1175 int opacity = (!topLevel || !GTK_IS_DIALOG(topLevel) ? 1176 opts.bgndOpacity : opts.dlgOpacity); 1177 int xmod = 0; 1178 int ymod = 0; 1179 int wmod = 0; 1180 int hmod = 0; 1181 double alpha = 1.0; 1182 bool useAlpha = (opacity < 100 && isRgbaWidget(topLevel) && 1183 compositingActive(topLevel)); 1184 bool flatBgnd = qtcIsFlatBgnd(opts.bgndAppearance); 1185 1186 // Determine the color to use here 1187 // In commit 87404dba2447c8cba1c70bde72434c67642a7e7c: 1188 // When drawing background gradients, use the background colour of 1189 // the top-level widget's style. 1190 // the order was set to Toplevel -> Parent -> Global style. 1191 // This cause wrong color to be used in chomium. 1192 // The current order is Parent -> Toplevel -> Global style. 1193 // Keep this order unless other problems are found. 1194 // It may also be a good idea to figure out what is the original color 1195 // and make the color of choice here consistent with that. 1196 // (at least for chromium) 1197 const GdkColor *col = getParentBgCol(widget); 1198 if (!col) { 1199 col = &qtcDefault(gtk_widget_get_style(topLevel), 1200 style)->bg[GTK_STATE_NORMAL]; 1201 } 1202 if (!flatBgnd || (opts.bgndImage.type == IMG_FILE && 1203 opts.bgndImage.onBorder)) { 1204 WindowBorders borders = qtcGetWindowBorderSize(false); 1205 xmod = borders.sides; 1206 ymod = borders.titleHeight; 1207 wmod = 2 * borders.sides; 1208 hmod = borders.titleHeight + borders.bottom; 1209 wy += ymod; 1210 wx += xmod; 1211 wh += hmod; 1212 ww += wmod; 1213 } 1214 QtcRect clip = {x, y, width, height}; 1215 Cairo::Saver saver(cr); 1216 Cairo::clipRect(cr, &clip); 1217 if (useAlpha) { 1218 alpha = opacity / 100.0; 1219 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); 1220 } 1221 if (flatBgnd) { 1222 Cairo::rect(cr, area, -wx, -wy, ww, wh, col, alpha); 1223 } else if (opts.bgndAppearance == APPEARANCE_STRIPED) { 1224 drawStripedBgnd(cr, -wx, -wy, ww, wh, col, alpha); 1225 } else if (opts.bgndAppearance == APPEARANCE_FILE) { 1226 Cairo::Saver saver(cr); 1227 cairo_translate(cr, -wx, -wy); 1228 drawBgndImage(cr, 0, 0, ww, wh, true); 1229 } else { 1230 drawBevelGradient(cr, area, -wx, -wy, ww, wh + 1, col, 1231 opts.bgndGrad == GT_HORIZ, false, 1232 opts.bgndAppearance, WIDGET_OTHER, alpha); 1233 if (opts.bgndGrad == GT_HORIZ && 1234 qtcGetGradient(opts.bgndAppearance, 1235 &opts)->border == GB_SHINE) { 1236 int size = qtcMin(BGND_SHINE_SIZE, qtcMin(wh * 2, ww)); 1237 double alpha = qtcShineAlpha(col); 1238 cairo_pattern_t *pat = nullptr; 1239 1240 size /= BGND_SHINE_STEPS; 1241 size *= BGND_SHINE_STEPS; 1242 pat = cairo_pattern_create_radial( 1243 ww / 2.0 - wx, -wy, 0, ww / 2.0 - wx, -wy, size / 2.0); 1244 cairo_pattern_add_color_stop_rgba(pat, 0, 1, 1, 1, alpha); 1245 cairo_pattern_add_color_stop_rgba(pat, 0.5, 1, 1, 1, 1246 alpha * 0.625); 1247 cairo_pattern_add_color_stop_rgba(pat, 0.75, 1, 1, 1, 1248 alpha * 0.175); 1249 cairo_pattern_add_color_stop_rgba(pat, CAIRO_GRAD_END, 1250 1, 1, 1, 0.0); 1251 cairo_set_source(cr, pat); 1252 cairo_rectangle(cr, (ww - size) / 2.0 - wx, -wy, size, size); 1253 cairo_fill(cr); 1254 cairo_pattern_destroy(pat); 1255 } 1256 } 1257 if (useAlpha) { 1258 cairo_set_operator(cr, CAIRO_OPERATOR_OVER); 1259 } 1260 if (!(opts.bgndImage.type == IMG_FILE && opts.bgndImage.onBorder)) { 1261 ww -= wmod + 1; 1262 wh -= hmod; 1263 wx -= xmod; 1264 wy -= ymod; 1265 } 1266 drawBgndRings(cr, -wx, -wy, ww, wh, true); 1267 return true; 1268 } 1269 return false; 1270 } 1271 1272 void 1273 drawEntryField(cairo_t *cr, GtkStyle *style, GtkStateType state, 1274 GdkWindow *window, GtkWidget *widget, const QtcRect *area, 1275 int x, int y, int width, int height, 1276 ECornerBits round, EWidget w) 1277 { 1278 bool enabled = !(GTK_STATE_INSENSITIVE == state || 1279 (widget && !gtk_widget_is_sensitive(widget))); 1280 bool highlightReal = 1281 (enabled && widget && gtk_widget_has_focus(widget) && 1282 qtSettings.app != GTK_APP_JAVA); 1283 bool mouseOver = 1284 (opts.unifyCombo && opts.unifySpin && enabled && 1285 (GTK_STATE_PRELIGHT == state || Entry::isLastMo(widget)) && 1286 qtcPalette.mouseover && GTK_APP_JAVA != qtSettings.app); 1287 bool highlight = highlightReal || mouseOver; 1288 bool doEtch = opts.buttonEffect != EFFECT_NONE && opts.etchEntry; 1289 bool comboOrSpin = oneOf(w, WIDGET_SPIN, WIDGET_COMBO_BUTTON); 1290 const GdkColor *colors = (mouseOver ? qtcPalette.mouseover : highlightReal ? 1291 qtcPalette.focus : qtcPalette.background); 1292 1293 if (qtSettings.app != GTK_APP_JAVA) { 1294 Entry::setup(widget); 1295 } 1296 if ((doEtch || opts.round != ROUND_NONE) && 1297 (!widget || !g_object_get_data(G_OBJECT(widget), 1298 "transparent-bg-hint"))) { 1299 if (qtcIsFlatBgnd(opts.bgndAppearance) || !widget || 1300 !drawWindowBgnd(cr, style, area, window, widget, x, y, 1301 width, height)) { 1302 GdkColor parentBgCol; 1303 getEntryParentBgCol(widget, &parentBgCol); 1304 drawEntryCorners(cr, area, round, x, y, width, height, 1305 &parentBgCol, 1.0); 1306 } 1307 } 1308 1309 if (opts.gbFactor != 0 && 1310 oneOf(opts.groupBox, FRAME_SHADED, FRAME_FADED) && 1311 isInGroupBox(widget, 0)) { 1312 GdkColor col; 1313 col.red = col.green = col.blue = opts.gbFactor < 0 ? 0.0 : 1.0; 1314 drawEntryCorners(cr, area, round, x, y, width, height, &col, 1315 TO_ALPHA(opts.gbFactor)); 1316 } 1317 1318 if (doEtch) { 1319 y++; 1320 x++; 1321 height -= 2; 1322 width -= 2; 1323 } 1324 1325 if (DEBUG_ALL == qtSettings.debug) { 1326 printf(DEBUG_PREFIX "%s %d %d %d %d %d %d ", __FUNCTION__, 1327 state, x, y, width, height, round); 1328 debugDisplayWidget(widget, 10); 1329 } 1330 1331 if (round != ROUNDED_ALL) { 1332 if (comboOrSpin) { 1333 x -= 2; 1334 width += 2; 1335 } else if (highlight) { 1336 if (doEtch) { 1337 if (round == ROUNDED_RIGHT) { 1338 /* RtoL */ 1339 x--; 1340 } else { 1341 width++; 1342 } 1343 } 1344 } else { 1345 if (round == ROUNDED_RIGHT) { 1346 /* RtoL */ 1347 x -= 2; 1348 } else { 1349 width += 2; 1350 } 1351 } 1352 } 1353 1354 Cairo::Saver saver(cr); 1355 if (opts.round > ROUND_FULL) { 1356 qtcClipPath(cr, x + 1, y + 1, width - 2, height - 2, 1357 WIDGET_ENTRY, RADIUS_INTERNAL, ROUNDED_ALL); 1358 } 1359 Cairo::rect(cr, area, x + 1, y + 1, width - 2, height - 2, 1360 enabled ? &style->base[GTK_STATE_NORMAL] : 1361 &style->bg[GTK_STATE_INSENSITIVE]); 1362 1363 saver.resave(); 1364 1365 if (qtSettings.app == GTK_APP_OPEN_OFFICE && comboOrSpin) { 1366 const QtcRect rect = {x, y, width, height}; 1367 x -= 4; 1368 width += 4; 1369 Cairo::clipRect(cr, &rect); 1370 } 1371 1372 int xo = x; 1373 int yo = y; 1374 int widtho = width; 1375 int heighto = height; 1376 1377 if (doEtch) { 1378 y--; 1379 height += 2; 1380 x--; 1381 width += 2; 1382 if (!(w == WIDGET_SPIN && opts.unifySpin) && 1383 !(w == WIDGET_COMBO_BUTTON && opts.unifyCombo)) { 1384 if (!(round & CORNER_TR) && !(round & CORNER_BR)) { 1385 width += 4; 1386 } 1387 if (!(round & CORNER_TL) && !(round & CORNER_BL)) { 1388 x -= 4; 1389 } 1390 } 1391 drawEtch(cr, area, widget, x, y, width, height, false, round, 1392 WIDGET_ENTRY); 1393 } 1394 1395 drawBorder(cr, style, (!widget || gtk_widget_is_sensitive(widget) ? 1396 state : GTK_STATE_INSENSITIVE), area, 1397 xo, yo, widtho, heighto, colors, round, 1398 BORDER_SUNKEN, WIDGET_ENTRY, DF_BLEND); 1399 if (GTK_IS_ENTRY(widget) && !gtk_entry_get_visibility(GTK_ENTRY(widget))) { 1400 gtk_entry_set_invisible_char(GTK_ENTRY(widget), opts.passwordChar); 1401 } 1402 } 1403 1404 static void 1405 qtcSetProgressStripeClipping(cairo_t *cr, const QtcRect *area, int x, int y, 1406 int width, int height, int animShift, bool horiz) 1407 { 1408 switch (opts.stripedProgress) { 1409 default: 1410 case STRIPE_PLAIN: { 1411 QtcRect rect = {x, y, width - 2, height - 2}; 1412 Rect::constrain(&rect, area); 1413 cairo_region_t *region = cairo_region_create_rectangle(&rect); 1414 if (horiz) { 1415 for (int stripeOffset = 0; 1416 stripeOffset < width + PROGRESS_CHUNK_WIDTH; 1417 stripeOffset += PROGRESS_CHUNK_WIDTH * 2) { 1418 QtcRect innerRect = {x + stripeOffset + animShift, y + 1, 1419 PROGRESS_CHUNK_WIDTH, height - 2}; 1420 Rect::constrain(&innerRect, area); 1421 if (innerRect.width > 0 && innerRect.height > 0) { 1422 cairo_region_xor_rectangle(region, &innerRect); 1423 } 1424 } 1425 } else { 1426 for (int stripeOffset = 0; 1427 stripeOffset < height + PROGRESS_CHUNK_WIDTH; 1428 stripeOffset += PROGRESS_CHUNK_WIDTH * 2) { 1429 QtcRect innerRect = {x + 1, y + stripeOffset + animShift, 1430 width - 2, PROGRESS_CHUNK_WIDTH}; 1431 /* qtcRectConstrain(&innerRect, area); */ 1432 if (innerRect.width > 0 && innerRect.height > 0) { 1433 cairo_region_xor_rectangle(region, &innerRect); 1434 } 1435 } 1436 } 1437 Cairo::clipRegion(cr, region); 1438 cairo_region_destroy(region); 1439 break; 1440 } 1441 case STRIPE_DIAGONAL: 1442 cairo_new_path(cr); 1443 /* if (area) */ 1444 /* cairo_rectangle(cr, area->x, area->y, */ 1445 /* area->width, area->height); */ 1446 if (horiz) { 1447 for (int stripeOffset = 0;stripeOffset < width + height + 2; 1448 stripeOffset += PROGRESS_CHUNK_WIDTH * 2) { 1449 const GdkPoint pts[4] = { 1450 {x + stripeOffset + animShift, y}, 1451 {x + stripeOffset + animShift + PROGRESS_CHUNK_WIDTH, y}, 1452 {x + stripeOffset + animShift + 1453 PROGRESS_CHUNK_WIDTH - height, y + height - 1}, 1454 {x + stripeOffset + animShift - height, y + height - 1}}; 1455 Cairo::pathPoints(cr, pts, 4); 1456 } 1457 } else { 1458 for (int stripeOffset = 0;stripeOffset < height + width + 2; 1459 stripeOffset += PROGRESS_CHUNK_WIDTH * 2) { 1460 const GdkPoint pts[4] = { 1461 {x, y + stripeOffset + animShift}, 1462 {x + width - 1, y + stripeOffset + animShift - width}, 1463 {x + width - 1, y + stripeOffset + animShift + 1464 PROGRESS_CHUNK_WIDTH - width}, 1465 {x, y + stripeOffset + animShift + PROGRESS_CHUNK_WIDTH}}; 1466 Cairo::pathPoints(cr, pts, 4); 1467 } 1468 } 1469 cairo_clip(cr); 1470 } 1471 } 1472 1473 void 1474 drawProgress(cairo_t *cr, GtkStyle *style, GtkStateType state, 1475 GtkWidget *widget, const QtcRect *area, int x, int y, 1476 int width, int height, bool rev, bool isEntryProg) 1477 { 1478 #if GTK_CHECK_VERSION(2, 90, 0) 1479 bool revProg = (widget && GTK_IS_PROGRESS_BAR(widget) && 1480 gtk_progress_bar_get_inverted(GTK_PROGRESS_BAR(widget))); 1481 #else 1482 GtkProgressBarOrientation orientation = 1483 (widget && GTK_IS_PROGRESS_BAR(widget) ? 1484 gtk_progress_bar_get_orientation(GTK_PROGRESS_BAR(widget)) : 1485 GTK_PROGRESS_LEFT_TO_RIGHT); 1486 bool revProg = oneOf(orientation, GTK_PROGRESS_RIGHT_TO_LEFT, 1487 GTK_PROGRESS_BOTTOM_TO_TOP); 1488 #endif 1489 const bool horiz = isHorizontalProgressbar(widget); 1490 EWidget wid = isEntryProg ? WIDGET_ENTRY_PROGRESSBAR : WIDGET_PROGRESSBAR; 1491 int animShift = revProg ? 0 : -PROGRESS_CHUNK_WIDTH; 1492 int xo = x; 1493 int yo = y; 1494 int wo = width; 1495 int ho = height; 1496 1497 if (opts.fillProgress) { 1498 x--; 1499 y--; 1500 width += 2; 1501 height += 2; 1502 xo = x; 1503 yo = y; 1504 wo = width; 1505 ho = height; 1506 } 1507 1508 if (opts.stripedProgress != STRIPE_NONE && 1509 opts.animatedProgress && (isEntryProg || qtcIsProgressBar(widget))) { 1510 #if !GTK_CHECK_VERSION(2, 90, 0) /* Gtk3:TODO !!! */ 1511 if (isEntryProg || !GTK_PROGRESS(widget)->activity_mode) 1512 #endif 1513 Animation::addProgressBar(widget, isEntryProg); 1514 1515 animShift+=(revProg ? -1 : 1)* 1516 (int(Animation::elapsed(widget) * PROGRESS_CHUNK_WIDTH) % 1517 (PROGRESS_CHUNK_WIDTH * 2)); 1518 } 1519 1520 bool grayItem = (state == GTK_STATE_INSENSITIVE && 1521 opts.progressGrooveColor != ECOLOR_BACKGROUND); 1522 const GdkColor *itemCols = (grayItem ? qtcPalette.background : 1523 qtcPalette.progress ? qtcPalette.progress : 1524 qtcPalette.highlight); 1525 auto new_state = GTK_STATE_PRELIGHT == state ? GTK_STATE_NORMAL : state; 1526 int fillVal = grayItem ? 4 : ORIGINAL_SHADE; 1527 1528 x++; 1529 y++; 1530 width -= 2; 1531 height -= 2; 1532 1533 Cairo::Saver saver(cr); 1534 if (opts.borderProgress && opts.round > ROUND_SLIGHT && 1535 (horiz ? width : height) < 4) { 1536 qtcClipPath(cr, x, y, width, height, wid, RADIUS_EXTERNAL, ROUNDED_ALL); 1537 } 1538 1539 if ((horiz ? width : height) > 1) 1540 drawLightBevel(cr, style, new_state, area, x, y, width, 1541 height, &itemCols[fillVal], itemCols, ROUNDED_ALL, 1542 wid, BORDER_FLAT, (horiz ? 0 : DF_VERT), widget); 1543 if (opts.stripedProgress && width > 4 && height > 4) { 1544 if (opts.stripedProgress == STRIPE_FADE) { 1545 int posMod = opts.animatedProgress ? STRIPE_WIDTH - animShift : 0; 1546 int sizeMod = opts.animatedProgress ? (STRIPE_WIDTH * 2) : 0; 1547 addStripes(cr, x - (horiz ? posMod : 0), y - (horiz ? 0 : posMod), 1548 width + (horiz ? sizeMod : 0), 1549 height + (horiz ? 0 : sizeMod), horiz); 1550 } else { 1551 Cairo::Saver saver(cr); 1552 qtcSetProgressStripeClipping(cr, area, xo, yo, wo, ho, 1553 animShift, horiz); 1554 drawLightBevel(cr, style, new_state, nullptr, x, y, 1555 width, height, &itemCols[1], qtcPalette.highlight, 1556 ROUNDED_ALL, wid, BORDER_FLAT, 1557 (opts.fillProgress || !opts.borderProgress ? 0 : 1558 DF_DO_BORDER) | (horiz ? 0 : DF_VERT), widget); 1559 } 1560 } 1561 if (opts.glowProgress && (horiz ? width : height)>3) { 1562 int offset = opts.borderProgress ? 1 : 0; 1563 cairo_pattern_t *pat = 1564 cairo_pattern_create_linear(x+offset, y+offset, horiz ? 1565 x + width - offset : x + offset, 1566 horiz ? y + offset : 1567 y + height - offset); 1568 bool inverted = false; 1569 1570 if (GLOW_MIDDLE != opts.glowProgress && widget && 1571 GTK_IS_PROGRESS_BAR(widget)) { 1572 if (horiz) { 1573 if (revProg) { 1574 inverted = !rev; 1575 } else { 1576 inverted = rev; 1577 } 1578 } else { 1579 inverted = revProg; 1580 } 1581 } 1582 1583 cairo_pattern_add_color_stop_rgba( 1584 pat, 0.0, 1.0, 1.0, 1.0, 1585 (inverted ? GLOW_END : GLOW_START) == opts.glowProgress ? 1586 GLOW_PROG_ALPHA : 0.0); 1587 1588 if (GLOW_MIDDLE == opts.glowProgress) 1589 cairo_pattern_add_color_stop_rgba(pat, 0.5, 1.0, 1.0, 1.0, 1590 GLOW_PROG_ALPHA); 1591 1592 cairo_pattern_add_color_stop_rgba( 1593 pat, CAIRO_GRAD_END, 1.0, 1.0, 1.0, 1594 (inverted ? GLOW_START : GLOW_END) == opts.glowProgress ? 1595 GLOW_PROG_ALPHA : 0.0); 1596 cairo_set_source(cr, pat); 1597 cairo_rectangle(cr, x + offset, y + offset, width - 2 * offset, 1598 height - 2 * offset); 1599 cairo_fill(cr); 1600 cairo_pattern_destroy(pat); 1601 if (width > 2 && height > 2 && opts.borderProgress) 1602 drawBorder(cr, style, state, area, x, y, width, height, 1603 itemCols, ROUNDED_ALL, BORDER_FLAT, wid, 1604 0, PBAR_BORDER); 1605 1606 if (!opts.borderProgress) { 1607 if (horiz) { 1608 Cairo::hLine(cr, x, y, width, &itemCols[PBAR_BORDER]); 1609 Cairo::hLine(cr, x, y + height - 1, width, 1610 &itemCols[PBAR_BORDER]); 1611 } else { 1612 Cairo::vLine(cr, x, y, height, &itemCols[PBAR_BORDER]); 1613 Cairo::vLine(cr, x + width - 1, y, height, 1614 &itemCols[PBAR_BORDER]); 1615 } 1616 } 1617 } 1618 } 1619 1620 void 1621 drawProgressGroove(cairo_t *cr, GtkStyle *style, GtkStateType state, 1622 GdkWindow *window, GtkWidget *widget, const QtcRect *area, 1623 int x, int y, int width, int height, bool isList, bool horiz) 1624 { 1625 bool doEtch = !isList && opts.buttonEffect != EFFECT_NONE; 1626 const GdkColor *col = &style->base[state]; 1627 int offset = opts.borderProgress ? 1 : 0; 1628 1629 switch (opts.progressGrooveColor) { 1630 default: 1631 case ECOLOR_BASE: 1632 col = &style->base[state]; 1633 break; 1634 case ECOLOR_BACKGROUND: 1635 col = &qtcPalette.background[ORIGINAL_SHADE]; 1636 break; 1637 case ECOLOR_DARK: 1638 col = &qtcPalette.background[2]; 1639 } 1640 1641 if (!isList && (qtcIsFlatBgnd(opts.bgndAppearance) || 1642 !(widget && drawWindowBgnd(cr, style, area, window, widget, 1643 x, y, width, height))) && 1644 (!widget || !g_object_get_data(G_OBJECT(widget), 1645 "transparent-bg-hint"))) { 1646 Cairo::rect(cr, area, x, y, width, height, 1647 &qtcPalette.background[ORIGINAL_SHADE]); 1648 } 1649 1650 if (doEtch && opts.borderProgress) { 1651 x++; 1652 y++; 1653 width -= 2; 1654 height -= 2; 1655 } 1656 1657 drawBevelGradient(cr, area, x + offset, y + offset, 1658 width - 2 * offset, height - 2 * offset, col, horiz, 1659 false, opts.progressGrooveAppearance, WIDGET_PBAR_TROUGH); 1660 1661 if (doEtch && opts.borderProgress) { 1662 drawEtch(cr, area, widget, x - 1, y - 1, width + 2, 1663 height + 2, false, ROUNDED_ALL, WIDGET_PBAR_TROUGH); 1664 } 1665 if (opts.borderProgress) { 1666 GtkWidget *parent = widget ? gtk_widget_get_parent(widget) : nullptr; 1667 GtkStyle *style = widget ? gtk_widget_get_style(parent ? 1668 parent : widget) : nullptr; 1669 drawBorder(cr, style, state, area, x, y, width, height, 1670 nullptr, ROUNDED_ALL, 1671 (qtcIsFlat(opts.progressGrooveAppearance) && 1672 opts.progressGrooveColor != ECOLOR_DARK ? 1673 BORDER_SUNKEN : BORDER_FLAT), 1674 WIDGET_PBAR_TROUGH, DF_BLEND); 1675 } else { /* if(!opts.borderProgress) */ 1676 if (horiz) { 1677 Cairo::hLine(cr, x, y, width, 1678 &qtcPalette.background[QTC_STD_BORDER]); 1679 Cairo::hLine(cr, x, y + height - 1, width, 1680 &qtcPalette.background[QTC_STD_BORDER]); 1681 } else { 1682 Cairo::vLine(cr, x, y, height, 1683 &qtcPalette.background[QTC_STD_BORDER]); 1684 Cairo::vLine(cr, x + width - 1, y, height, 1685 &qtcPalette.background[QTC_STD_BORDER]); 1686 } 1687 } 1688 } 1689 1690 #define SLIDER_TROUGH_SIZE 5 1691 1692 void 1693 drawSliderGroove(cairo_t *cr, GtkStyle *style, GtkStateType state, 1694 GtkWidget *widget, const char *detail, 1695 const QtcRect *area, int x, int y, int width, int height, 1696 bool horiz) 1697 { 1698 const GdkColor *bgndcols = qtcPalette.background; 1699 const GdkColor *bgndcol = &bgndcols[2]; 1700 GtkAdjustment *adjustment = gtk_range_get_adjustment(GTK_RANGE(widget)); 1701 double upper = gtk_adjustment_get_upper(adjustment); 1702 double lower = gtk_adjustment_get_lower(adjustment); 1703 double value = gtk_adjustment_get_value(adjustment); 1704 int used_x = x; 1705 int used_y = y; 1706 int used_h = 0; 1707 int used_w = 0; 1708 int pos = (int)(((double)(horiz ? width : height) / 1709 (upper - lower)) * (value - lower)); 1710 bool inverted = gtk_range_get_inverted(GTK_RANGE(widget)); 1711 bool doEtch = opts.buttonEffect != EFFECT_NONE; 1712 bool rev = (reverseLayout(widget) || 1713 (widget && reverseLayout(gtk_widget_get_parent(widget)))); 1714 int troughSize = SLIDER_TROUGH_SIZE + (doEtch ? 2 : 0); 1715 const GdkColor *usedcols = 1716 (opts.fillSlider && upper != lower && state != GTK_STATE_INSENSITIVE ? 1717 qtcPalette.slider ? qtcPalette.slider : qtcPalette.highlight : 1718 qtcPalette.background); 1719 EWidget wid = WIDGET_SLIDER_TROUGH; 1720 1721 if (horiz && rev) 1722 inverted = !inverted; 1723 1724 if (horiz) { 1725 y += (height - troughSize) / 2; 1726 height = troughSize; 1727 used_y = y; 1728 used_h = height; 1729 } else { 1730 x += (width - troughSize) / 2; 1731 width = troughSize; 1732 used_x = x; 1733 used_w = width; 1734 } 1735 1736 if (state == GTK_STATE_INSENSITIVE) { 1737 bgndcol = &bgndcols[ORIGINAL_SHADE]; 1738 } else if (oneOf(detail, "trough-lower") && opts.fillSlider) { 1739 bgndcols = usedcols; 1740 bgndcol = &usedcols[ORIGINAL_SHADE]; 1741 wid = WIDGET_FILLED_SLIDER_TROUGH; 1742 } 1743 drawLightBevel(cr, style, state, area, x, y, width, height, bgndcol, 1744 bgndcols, (opts.square & SQUARE_SLIDER ? ROUNDED_NONE : 1745 ROUNDED_ALL), wid, BORDER_FLAT, 1746 DF_SUNKEN | DF_DO_BORDER | (horiz ? 0 : DF_VERT), nullptr); 1747 1748 if (opts.fillSlider && upper != lower && 1749 state != GTK_STATE_INSENSITIVE && oneOf(detail, "trough")) { 1750 if (horiz) { 1751 pos += width > 10 && pos < width / 2 ? 3 : 0; 1752 1753 if (inverted) { 1754 /* <rest><slider><used> */ 1755 used_x += width - pos; 1756 } 1757 used_w = pos; 1758 } else { 1759 pos += height > 10 && pos < height / 2 ? 3 : 0; 1760 1761 if (inverted) { 1762 used_y += height - pos; 1763 } 1764 used_h = pos; 1765 } 1766 1767 if (used_w > 0 && used_h > 0) { 1768 drawLightBevel(cr, style, state, area, used_x, used_y, used_w, 1769 used_h, &usedcols[ORIGINAL_SHADE], usedcols, 1770 opts.square & SQUARE_SLIDER ? ROUNDED_NONE : 1771 ROUNDED_ALL, WIDGET_FILLED_SLIDER_TROUGH, 1772 BORDER_FLAT, DF_SUNKEN | DF_DO_BORDER | 1773 (horiz ? 0 : DF_VERT), nullptr); 1774 } 1775 } 1776 } 1777 1778 void 1779 drawTriangularSlider(cairo_t *cr, GtkStyle *style, GtkStateType state, 1780 const char *detail, int x, int y, int width, int height) 1781 { 1782 GdkColor newColors[TOTAL_SHADES + 1]; 1783 const GdkColor *btnColors = nullptr; 1784 1785 /* Fix Java swing sliders looking pressed */ 1786 if (state == GTK_STATE_ACTIVE) 1787 state = GTK_STATE_PRELIGHT; 1788 1789 if (useButtonColor(detail)) { 1790 if (state == GTK_STATE_INSENSITIVE) { 1791 btnColors = qtcPalette.background; 1792 } else if (QT_CUSTOM_COLOR_BUTTON(style)) { 1793 shadeColors(&style->bg[state], newColors); 1794 btnColors = newColors; 1795 } else { 1796 GtkWidget *widget = nullptr; /* Keep SET_BTN_COLS happy */ 1797 SET_BTN_COLS(false, true, false, state); 1798 } 1799 } 1800 1801 bool coloredMouseOver = (state == GTK_STATE_PRELIGHT && 1802 opts.coloredMouseOver && 1803 !opts.colorSliderMouseOver); 1804 bool horiz = height > width || oneOf(detail, "hscale"); 1805 int bgnd = getFill(state, false, opts.shadeSliders == SHADE_DARKEN); 1806 int xo = horiz ? 8 : 0; 1807 int yo = horiz ? 0 : 8; 1808 int size = 15; 1809 int light = opts.sliderAppearance == APPEARANCE_DULL_GLASS ? 1 : 0; 1810 const GdkColor *colors = btnColors; 1811 const GdkColor *borderCols = ((GTK_STATE_PRELIGHT == state && 1812 oneOf(opts.coloredMouseOver, MO_GLOW, 1813 MO_COLORED)) ? 1814 qtcPalette.mouseover : btnColors); 1815 GtkArrowType direction = horiz ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT; 1816 bool drawLight = opts.coloredMouseOver != MO_PLASTIK || !coloredMouseOver; 1817 int borderVal = (qtcPalette.mouseover == borderCols ? SLIDER_MO_BORDER_VAL : 1818 BORDER_VAL(state == GTK_STATE_INSENSITIVE)); 1819 if (opts.coloredMouseOver == MO_GLOW && opts.buttonEffect != EFFECT_NONE) { 1820 x++; 1821 y++; 1822 xo++; 1823 yo++; 1824 } 1825 cairo_new_path(cr); 1826 cairo_save(cr); 1827 switch (direction) { 1828 case GTK_ARROW_UP: 1829 default: 1830 case GTK_ARROW_DOWN: { 1831 y += 2; 1832 const GdkPoint pts[] = {{x, y}, {x, y + 2}, {x + 2, y}, {x + 8, y}, 1833 {x + 10, y + 2}, {x + 10, y + 9}, 1834 {x + 5, y + 14}, {x, y + 9}}; 1835 Cairo::pathPoints(cr, pts, 8); 1836 break; 1837 } 1838 case GTK_ARROW_RIGHT: 1839 case GTK_ARROW_LEFT: { 1840 x+=2; 1841 const GdkPoint pts[] = {{x, y}, {x + 2, y}, {x, y + 2}, {x, y + 8}, 1842 {x + 2, y + 10}, {x + 9, y + 10}, 1843 {x + 14, y + 5}, {x + 9, y}}; 1844 Cairo::pathPoints(cr, pts, 8); 1845 } 1846 } 1847 cairo_clip(cr); 1848 if (qtcIsFlat(opts.sliderAppearance)) { 1849 Cairo::rect(cr, nullptr, x + 1, y + 1, width - 2, height - 2, 1850 &colors[bgnd]); 1851 if (MO_PLASTIK == opts.coloredMouseOver && coloredMouseOver) { 1852 int col = SLIDER_MO_SHADE; 1853 int len = SLIDER_MO_LEN; 1854 if (horiz) { 1855 Cairo::rect(cr, nullptr, x + 1, y + 1, len, size - 2, 1856 &qtcPalette.mouseover[col]); 1857 Cairo::rect(cr, nullptr, x + width - (1 + len), y + 1, len, 1858 size - 2, &qtcPalette.mouseover[col]); 1859 } else { 1860 Cairo::rect(cr, nullptr, x + 1, y + 1, size - 2, len, 1861 &qtcPalette.mouseover[col]); 1862 Cairo::rect(cr, nullptr, x + 1, y + height - (1 + len), size - 2, 1863 len, &qtcPalette.mouseover[col]); 1864 } 1865 } 1866 } else { 1867 drawBevelGradient(cr, nullptr, x, y, horiz ? width - 1 : size, 1868 horiz ? size : height - 1, &colors[bgnd], 1869 horiz, false, MODIFY_AGUA(opts.sliderAppearance), 1870 WIDGET_OTHER); 1871 if (opts.coloredMouseOver == MO_PLASTIK && coloredMouseOver) { 1872 int col = SLIDER_MO_SHADE; 1873 int len = SLIDER_MO_LEN; 1874 if (horiz) { 1875 drawBevelGradient(cr, nullptr, x + 1, y + 1, len, size - 2, 1876 &qtcPalette.mouseover[col], horiz, false, 1877 MODIFY_AGUA(opts.sliderAppearance), 1878 WIDGET_OTHER); 1879 drawBevelGradient(cr, nullptr, x + width - (1 + len), y + 1, len, 1880 size - 2, &qtcPalette.mouseover[col], horiz, 1881 false, MODIFY_AGUA(opts.sliderAppearance), 1882 WIDGET_OTHER); 1883 } else { 1884 drawBevelGradient(cr, nullptr, x + 1, y + 1, size - 2, len, 1885 &qtcPalette.mouseover[col], horiz, false, 1886 MODIFY_AGUA(opts.sliderAppearance), 1887 WIDGET_OTHER); 1888 drawBevelGradient(cr, nullptr, x + 1, y + height - (1 + len), 1889 size - 2, len, &qtcPalette.mouseover[col], 1890 horiz, false, 1891 MODIFY_AGUA(opts.sliderAppearance), 1892 WIDGET_OTHER); 1893 } 1894 } 1895 } 1896 cairo_restore(cr); 1897 double xd = x + 0.5; 1898 double yd = y + 0.5; 1899 double radius = 2.5; 1900 double xdg = xd - 1; 1901 double ydg = yd - 1; 1902 double radiusg = radius + 1; 1903 bool glowMo = (opts.coloredMouseOver == MO_GLOW && 1904 coloredMouseOver && opts.buttonEffect != EFFECT_NONE); 1905 cairo_new_path(cr); 1906 if (glowMo) { 1907 Cairo::setColor(cr, &borderCols[GLOW_MO], GLOW_ALPHA(false)); 1908 } else { 1909 Cairo::setColor(cr, &borderCols[borderVal]); 1910 } 1911 switch (direction) { 1912 case GTK_ARROW_UP: 1913 default: 1914 case GTK_ARROW_DOWN: 1915 if (glowMo) { 1916 cairo_move_to(cr, xdg + radiusg, ydg); 1917 cairo_arc(cr, xdg + 12 - radiusg, ydg + radiusg, radiusg, 1918 M_PI * 1.5, M_PI * 2); 1919 cairo_line_to(cr, xdg + 12, ydg + 10.5); 1920 cairo_line_to(cr, xdg + 6, ydg + 16.5); 1921 cairo_line_to(cr, xdg, ydg + 10.5); 1922 cairo_arc(cr, xdg + radiusg, ydg + radiusg, radiusg, 1923 M_PI, M_PI * 1.5); 1924 cairo_stroke(cr); 1925 Cairo::setColor(cr, &borderCols[borderVal]); 1926 } 1927 cairo_move_to(cr, xd + radius, yd); 1928 cairo_arc(cr, xd + 10 - radius, yd + radius, radius, 1929 M_PI * 1.5, M_PI * 2); 1930 cairo_line_to(cr, xd + 10, yd + 9); 1931 cairo_line_to(cr, xd + 5, yd + 14); 1932 cairo_line_to(cr, xd, yd + 9); 1933 cairo_arc(cr, xd + radius, yd + radius, radius, M_PI, M_PI * 1.5); 1934 cairo_stroke(cr); 1935 if (drawLight) { 1936 Cairo::vLine(cr, xd + 1, yd + 2, 7, &colors[light]); 1937 Cairo::hLine(cr, xd + 2, yd + 1, 6, &colors[light]); 1938 } 1939 break; 1940 case GTK_ARROW_RIGHT: 1941 case GTK_ARROW_LEFT: 1942 if (glowMo) { 1943 cairo_move_to(cr, xdg, ydg + 12-radiusg); 1944 cairo_arc(cr, xdg + radiusg, ydg + radiusg, 1945 radiusg, M_PI, M_PI * 1.5); 1946 cairo_line_to(cr, xdg + 10.5, ydg); 1947 cairo_line_to(cr, xdg + 16.5, ydg + 6); 1948 cairo_line_to(cr, xdg + 10.5, ydg + 12); 1949 cairo_arc(cr, xdg + radiusg, ydg + 12 - radiusg, 1950 radiusg, M_PI * 0.5, M_PI); 1951 cairo_stroke(cr); 1952 Cairo::setColor(cr, &borderCols[borderVal]); 1953 } 1954 cairo_move_to(cr, xd, yd + 10 - radius); 1955 cairo_arc(cr, xd + radius, yd + radius, radius, M_PI, M_PI * 1.5); 1956 cairo_line_to(cr, xd + 9, yd); 1957 cairo_line_to(cr, xd + 14, yd + 5); 1958 cairo_line_to(cr, xd + 9, yd + 10); 1959 cairo_arc(cr, xd + radius, yd + 10 - radius, radius, M_PI * 0.5, M_PI); 1960 cairo_stroke(cr); 1961 if (drawLight) { 1962 Cairo::hLine(cr, xd + 2, yd + 1, 7, &colors[light]); 1963 Cairo::vLine(cr, xd + 1, yd + 2, 6, &colors[light]); 1964 } 1965 } 1966 } 1967 1968 void 1969 drawScrollbarGroove(cairo_t *cr, GtkStyle *style, GtkStateType state, 1970 GtkWidget *widget, const QtcRect *area, int x, int y, 1971 int width, int height, bool horiz) 1972 { 1973 ECornerBits sbarRound = ROUNDED_ALL; 1974 int xo = x; 1975 int yo = y; 1976 int wo = width; 1977 int ho = height; 1978 bool drawBg = opts.flatSbarButtons; 1979 bool thinner = (opts.thinSbarGroove && 1980 (opts.scrollbarType == SCROLLBAR_NONE || 1981 opts.flatSbarButtons)); 1982 1983 if (opts.flatSbarButtons) { 1984 #if GTK_CHECK_VERSION(2, 90, 0) 1985 bool lower = detail && strstr(detail, "-lower"); 1986 sbarRound = (lower ? horiz ? ROUNDED_LEFT : ROUNDED_TOP : horiz ? 1987 ROUNDED_RIGHT : ROUNDED_BOTTOM); 1988 1989 switch (opts.scrollbarType) { 1990 case SCROLLBAR_KDE: 1991 if (lower) { 1992 if (horiz) { 1993 x += opts.sliderWidth; 1994 } else { 1995 y += opts.sliderWidth; 1996 } 1997 } else { 1998 if (horiz) { 1999 width -= opts.sliderWidth * 2; 2000 } else { 2001 height -= opts.sliderWidth * 2; 2002 } 2003 } 2004 break; 2005 case SCROLLBAR_WINDOWS: 2006 if (lower) { 2007 if (horiz) { 2008 x += opts.sliderWidth; 2009 } else { 2010 y += opts.sliderWidth; 2011 } 2012 } else { 2013 if (horiz) { 2014 width -= opts.sliderWidth; 2015 } else { 2016 height -= opts.sliderWidth; 2017 } 2018 } 2019 break; 2020 case SCROLLBAR_NEXT: 2021 if (lower) { 2022 if (horiz) { 2023 x += opts.sliderWidth * 2; 2024 } else { 2025 y += opts.sliderWidth * 2; 2026 } 2027 } 2028 break; 2029 case SCROLLBAR_PLATINUM: 2030 if (!lower) { 2031 if (horiz) { 2032 width -= opts.sliderWidth * 2; 2033 } else { 2034 height -= opts.sliderWidth * 2; 2035 } 2036 } 2037 break; 2038 } 2039 #else 2040 switch (opts.scrollbarType) { 2041 case SCROLLBAR_KDE: 2042 if (horiz) { 2043 x += opts.sliderWidth; 2044 width -= opts.sliderWidth * 3; 2045 } else { 2046 y += opts.sliderWidth; 2047 height -= opts.sliderWidth * 3; 2048 } 2049 break; 2050 case SCROLLBAR_WINDOWS: 2051 if (horiz) { 2052 x += opts.sliderWidth; 2053 width -= opts.sliderWidth * 2; 2054 } else { 2055 y += opts.sliderWidth; 2056 height -= opts.sliderWidth * 2; 2057 } 2058 break; 2059 case SCROLLBAR_NEXT: 2060 if (horiz) { 2061 x+=opts.sliderWidth * 2; 2062 width -= opts.sliderWidth * 2; 2063 } else { 2064 y += opts.sliderWidth * 2; 2065 height -= opts.sliderWidth * 2; 2066 } 2067 break; 2068 case SCROLLBAR_PLATINUM: 2069 if (horiz) { 2070 width -= opts.sliderWidth * 2; 2071 } else { 2072 height -= opts.sliderWidth * 2; 2073 } 2074 break; 2075 default: 2076 break; 2077 } 2078 #endif 2079 } else { 2080 switch (opts.scrollbarType) { 2081 default: 2082 break; 2083 case SCROLLBAR_NEXT: 2084 sbarRound = horiz ? ROUNDED_LEFT : ROUNDED_TOP; 2085 break; 2086 case SCROLLBAR_PLATINUM: 2087 sbarRound = horiz ? ROUNDED_RIGHT : ROUNDED_BOTTOM; 2088 break; 2089 #ifdef SIMPLE_SCROLLBARS 2090 case SCROLLBAR_NONE: 2091 sbarRound = ROUNDED_NONE; 2092 break; 2093 #endif 2094 } 2095 } 2096 2097 if (opts.square & SQUARE_SB_SLIDER) 2098 sbarRound = ROUNDED_NONE; 2099 2100 if (drawBg) { 2101 GtkWidget *parent=nullptr; 2102 if (opts.gtkScrollViews && qtcIsFlat(opts.sbarBgndAppearance) && 2103 opts.tabBgnd != 0 && widget && 2104 (parent = gtk_widget_get_parent(widget)) && 2105 GTK_IS_SCROLLED_WINDOW(parent) && 2106 (parent = gtk_widget_get_parent(parent)) && 2107 GTK_IS_NOTEBOOK(parent)) { 2108 drawAreaModColor(cr, area, &qtcPalette.background[ORIGINAL_SHADE], 2109 TO_FACTOR(opts.tabBgnd), xo, yo, wo, ho); 2110 } else if (!qtcIsFlat(opts.sbarBgndAppearance) || 2111 !opts.gtkScrollViews) { 2112 drawBevelGradient(cr, area, xo, yo, wo, ho, 2113 &qtcPalette.background[ORIGINAL_SHADE], horiz, 2114 false, opts.sbarBgndAppearance, WIDGET_SB_BGND); 2115 } 2116 #if !GTK_CHECK_VERSION(2, 90, 0) 2117 /* This was the old (pre 1.7.1) else if... but it messes up Gtk3 scrollbars wheb have custom background. And dont think its needed */ 2118 /* But re-added in 1.7.2 for Mozilla! */ 2119 /* else if(!qtcIsCustomBgnd(&opts) || !(opts.gtkScrollViews && qtcIsFlat(opts.sbarBgndAppearance) && 2120 widget && drawWindowBgnd(cr, style, area, widget, xo, yo, wo, ho))) 2121 */ else if (isMozilla()) { 2122 /* 1.7.3 added 'else' so as to not duplicate above! */ 2123 drawBevelGradient(cr, area, xo, yo, wo, ho, 2124 &qtcPalette.background[ORIGINAL_SHADE], horiz, 2125 false, opts.sbarBgndAppearance, WIDGET_SB_BGND); 2126 } 2127 #endif 2128 } 2129 2130 if (isMozilla()) { 2131 if (!drawBg) { 2132 const GdkColor *parent_col = getParentBgCol(widget); 2133 const GdkColor *bgnd_col = 2134 (parent_col ? parent_col : 2135 &qtcPalette.background[ORIGINAL_SHADE]); 2136 2137 Cairo::Saver saver(cr); 2138 Cairo::clipRect(cr, area); 2139 Cairo::rect(cr, area, x, y, width, height, 2140 &qtcPalette.background[ORIGINAL_SHADE]); 2141 if (horiz) { 2142 if (oneOf(sbarRound, ROUNDED_LEFT, ROUNDED_ALL)) { 2143 Cairo::vLine(cr, x, y, height, bgnd_col); 2144 } 2145 if (oneOf(sbarRound, ROUNDED_RIGHT, ROUNDED_ALL)) { 2146 Cairo::vLine(cr, x + width - 1, y, height, bgnd_col); 2147 } 2148 } else { 2149 if (oneOf(sbarRound, ROUNDED_TOP, ROUNDED_ALL)) { 2150 Cairo::hLine(cr, x, y, width, bgnd_col); 2151 } 2152 if (oneOf(sbarRound, ROUNDED_BOTTOM, ROUNDED_ALL)) { 2153 Cairo::hLine(cr, x, y + height - 1, width, bgnd_col); 2154 } 2155 } 2156 } 2157 } else if (qtSettings.app == GTK_APP_OPEN_OFFICE && 2158 opts.flatSbarButtons && isFixedWidget(widget)) { 2159 if (horiz) { 2160 width--; 2161 } else { 2162 height--; 2163 } 2164 } 2165 2166 if (thinner && !drawBg) 2167 drawBgnd(cr, &qtcPalette.background[ORIGINAL_SHADE], widget, 2168 area, x, y, width, height); 2169 2170 drawLightBevel(cr, style, state, area, 2171 thinner && !horiz ? x + THIN_SBAR_MOD : x, 2172 thinner && horiz ? y + THIN_SBAR_MOD : y, 2173 thinner && !horiz ? width - THIN_SBAR_MOD * 2 : width, 2174 thinner && horiz ? height - THIN_SBAR_MOD * 2 : height, 2175 &qtcPalette.background[2], qtcPalette.background, sbarRound, 2176 thinner ? WIDGET_SLIDER_TROUGH : WIDGET_TROUGH, 2177 BORDER_FLAT, DF_SUNKEN | DF_DO_BORDER| 2178 (horiz ? 0 : DF_VERT), widget); 2179 } 2180 2181 void 2182 drawSelectionGradient(cairo_t *cr, const QtcRect *area, int x, int y, 2183 int width, int height, ECornerBits round, 2184 bool isLvSelection, double alpha, const GdkColor *col, 2185 bool horiz) 2186 { 2187 Cairo::Saver saver(cr); 2188 if ((!isLvSelection || !(opts.square & SQUARE_LISTVIEW_SELECTION)) && 2189 opts.round != ROUND_NONE) { 2190 Cairo::clipWhole(cr, x, y, width, height, 2191 qtcGetRadius(&opts, width, height, WIDGET_SELECTION, 2192 RADIUS_SELECTION), round); 2193 } 2194 drawBevelGradient(cr, area, x, y, width, height, col, horiz, false, 2195 opts.selectionAppearance, WIDGET_SELECTION, alpha); 2196 } 2197 2198 void 2199 drawSelection(cairo_t *cr, GtkStyle *style, GtkStateType state, 2200 const QtcRect *area, GtkWidget *widget, int x, int y, int width, 2201 int height, ECornerBits round, bool isLvSelection, 2202 double alphaMod, int factor) 2203 { 2204 bool hasFocus = gtk_widget_has_focus(widget); 2205 double alpha = (alphaMod * (state == GTK_STATE_PRELIGHT ? 0.20 : 1.0) * 2206 (hasFocus || !qtSettings.inactiveChangeSelectionColor ? 2207 1.0 : INACTIVE_SEL_ALPHA)); 2208 GdkColor col = style->base[hasFocus ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE]; 2209 2210 if (factor != 0) { 2211 col = shadeColor(&col, TO_FACTOR(factor)); 2212 } 2213 drawSelectionGradient(cr, area, x, y, width, height, round, 2214 isLvSelection, alpha, &col, true); 2215 2216 if (opts.borderSelection && 2217 (!isLvSelection || !(opts.square & SQUARE_LISTVIEW_SELECTION))) { 2218 double xd = x + 0.5; 2219 double yd = y + 0.5; 2220 double alpha = (state == GTK_STATE_PRELIGHT || alphaMod < 1.0 ? 2221 0.20 : 1.0); 2222 int xo = x; 2223 int widtho = width; 2224 2225 if (isLvSelection && !(opts.square & SQUARE_LISTVIEW_SELECTION) && 2226 round != ROUNDED_ALL) { 2227 if (!(round & ROUNDED_LEFT)) { 2228 x -= 1; 2229 xd -= 1; 2230 width += 1; 2231 } 2232 if (!(round & ROUNDED_RIGHT)) { 2233 width += 1; 2234 } 2235 } 2236 2237 Cairo::Saver saver(cr); 2238 cairo_new_path(cr); 2239 cairo_rectangle(cr, xo, y, widtho, height); 2240 cairo_clip(cr); 2241 Cairo::setColor(cr, &col, alpha); 2242 Cairo::pathWhole(cr, xd, yd, width - 1, height - 1, 2243 qtcGetRadius(&opts, widtho, height, WIDGET_OTHER, 2244 RADIUS_SELECTION), round); 2245 cairo_stroke(cr); 2246 } 2247 } 2248 2249 void 2250 createRoundedMask(GtkWidget *widget, int x, int y, int width, 2251 int height, double radius, bool isToolTip) 2252 { 2253 if (widget) { 2254 int size = ((width & 0xFFFF) << 16) + (height & 0xFFFF); 2255 GtkWidgetProps props(widget); 2256 int old = props->widgetMask; 2257 2258 if (size != old) { 2259 #if GTK_CHECK_VERSION(2, 90, 0) 2260 GdkRegion *mask = windowMask(0, 0, width, height, 2261 opts.round > ROUND_SLIGHT); 2262 2263 gtk_widget_shape_combine_region(widget, nullptr); 2264 gtk_widget_shape_combine_region(widget, mask); 2265 gdk_region_destroy(mask); 2266 #else 2267 GdkBitmap *mask = gdk_pixmap_new(nullptr, width, height, 1); 2268 cairo_t *crMask = gdk_cairo_create((GdkDrawable*)mask); 2269 2270 cairo_rectangle(crMask, 0, 0, width, height); 2271 cairo_set_source_rgba(crMask, 1, 1, 1, 0); 2272 cairo_set_operator(crMask, CAIRO_OPERATOR_SOURCE); 2273 cairo_paint(crMask); 2274 cairo_new_path(crMask); 2275 Cairo::pathWhole(crMask, 0, 0, width, height, radius, ROUNDED_ALL); 2276 cairo_set_source_rgba(crMask, 0, 0, 0, 1); 2277 cairo_fill(crMask); 2278 if (isToolTip) { 2279 gtk_widget_shape_combine_mask(widget, mask, x, y); 2280 } else { 2281 gdk_window_shape_combine_mask( 2282 gtk_widget_get_parent_window(widget), mask, 0, 0); 2283 } 2284 cairo_destroy(crMask); 2285 gdk_pixmap_unref(mask); 2286 #endif 2287 props->widgetMask = size; 2288 /* Setting the window type to 'popup menu' seems to 2289 re-eanble kwin shadows! */ 2290 if (isToolTip && gtk_widget_get_window(widget)) { 2291 gdk_window_set_type_hint(gtk_widget_get_window(widget), 2292 GDK_WINDOW_TYPE_HINT_POPUP_MENU); 2293 } 2294 } 2295 } 2296 } 2297 2298 void 2299 clearRoundedMask(GtkWidget *widget, bool isToolTip) 2300 { 2301 if (widget) { 2302 GtkWidgetProps props(widget); 2303 if (props->widgetMask) { 2304 #if GTK_CHECK_VERSION(2, 90, 0) 2305 gtk_widget_shape_combine_region(widget, nullptr); 2306 #else 2307 if(isToolTip) 2308 gtk_widget_shape_combine_mask(widget, nullptr, 0, 0); 2309 else 2310 gdk_window_shape_combine_mask(gtk_widget_get_parent_window(widget), nullptr, 0, 0); 2311 #endif 2312 props->widgetMask = 0; 2313 } 2314 } 2315 } 2316 2317 void 2318 drawTreeViewLines(cairo_t *cr, const GdkColor *col, int x, int y, int h, 2319 int depth, int levelIndent, int expanderSize, 2320 GtkTreeView *treeView, GtkTreePath *path) 2321 { 2322 int cellIndent = levelIndent + expanderSize + 4; 2323 int xStart = x + cellIndent / 2; 2324 int isLastMask = 0; 2325 bool haveChildren = treeViewCellHasChildren(treeView, path); 2326 bool useBitMask = depth < 33; 2327 GByteArray *isLast = (depth && !useBitMask ? 2328 g_byte_array_sized_new(depth) : nullptr); 2329 2330 if (useBitMask || isLast) { 2331 GtkTreePath *p = path ? gtk_tree_path_copy(path) : nullptr; 2332 int index=depth-1; 2333 2334 while (p && gtk_tree_path_get_depth(p) > 0 && index>=0) { 2335 GtkTreePath *next=treeViewPathParent(treeView, p); 2336 uint8_t last=treeViewCellIsLast(treeView, p) ? 1 : 0; 2337 if (useBitMask) { 2338 if (last) { 2339 isLastMask |= 1 << index; 2340 } 2341 } else { 2342 isLast = g_byte_array_prepend(isLast, &last, 1); 2343 } 2344 gtk_tree_path_free(p); 2345 p = next; 2346 index--; 2347 } 2348 Cairo::setColor(cr, col); 2349 for(int i = 0;i < depth;++i) { 2350 bool isLastCell = ((useBitMask ? isLastMask & (1 << i) : 2351 isLast->data[i]) ? true : false); 2352 bool last = i == depth - 1; 2353 double xCenter = xStart; 2354 if (last) { 2355 double yCenter = (int)(y + h / 2); 2356 2357 if (haveChildren) { 2358 // first vertical line 2359 cairo_move_to(cr, xCenter + 0.5, y); 2360 // (int)(expanderSize/3)); 2361 cairo_line_to(cr, xCenter + 0.5, yCenter - (LV_SIZE - 1)); 2362 // second vertical line 2363 if (!isLastCell) { 2364 cairo_move_to(cr, xCenter + 0.5, y + h); 2365 cairo_line_to(cr, xCenter + 0.5, 2366 yCenter + LV_SIZE + 1); 2367 } 2368 2369 // horizontal line 2370 cairo_move_to(cr, xCenter + (int)(expanderSize / 3) + 1, 2371 yCenter + 0.5); 2372 cairo_line_to(cr, xCenter + expanderSize * 2 / 3 - 1, 2373 yCenter + 0.5); 2374 } else { 2375 cairo_move_to(cr, xCenter + 0.5, y); 2376 if(isLastCell) { 2377 cairo_line_to(cr, xCenter + 0.5, yCenter); 2378 } else { 2379 cairo_line_to(cr, xCenter + 0.5, y + h); 2380 } 2381 // horizontal line 2382 cairo_move_to(cr, xCenter, yCenter + 0.5); 2383 cairo_line_to(cr, xCenter + expanderSize * 2 / 3 - 1, 2384 yCenter + 0.5); 2385 } 2386 } else if (!isLastCell) { 2387 // vertical line 2388 cairo_move_to(cr, xCenter + 0.5, y); 2389 cairo_line_to(cr, xCenter + 0.5, y + h); 2390 } 2391 cairo_stroke(cr); 2392 xStart += cellIndent; 2393 } 2394 if (isLast) { 2395 g_byte_array_free(isLast, false); 2396 } 2397 } 2398 } 2399 2400 static void 2401 qtcSetGapClip(cairo_t *cr, const QtcRect *area, GtkPositionType gapSide, 2402 int gapX, int gapWidth, int x, int y, int width, int height, 2403 bool isTab) 2404 { 2405 if (gapWidth <= 0) { 2406 return; 2407 } 2408 QtcRect gapRect; 2409 int adjust = isTab ? (gapX > 1 ? 1 : 2) : 0; 2410 switch (gapSide) { 2411 case GTK_POS_TOP: 2412 gapRect = qtcRect(x + gapX + adjust, y, gapWidth - 2 * adjust, 2); 2413 if (qtSettings.app == GTK_APP_JAVA && isTab) { 2414 gapRect.width -= 3; 2415 } 2416 break; 2417 case GTK_POS_BOTTOM: 2418 gapRect = qtcRect(x + gapX + adjust, y + height - 2, 2419 gapWidth - 2 * adjust, 2); 2420 break; 2421 case GTK_POS_LEFT: 2422 gapRect = qtcRect(x, y + gapX + adjust, 2, gapWidth - 2 * adjust); 2423 break; 2424 case GTK_POS_RIGHT: 2425 gapRect = qtcRect(x + width - 2, y + gapX + adjust, 2426 2, gapWidth - 2 * adjust); 2427 break; 2428 } 2429 2430 QtcRect r = {x, y, width, height}; 2431 cairo_region_t *region = cairo_region_create_rectangle(area ? area : &r); 2432 cairo_region_xor_rectangle(region, &gapRect); 2433 Cairo::clipRegion(cr, region); 2434 cairo_region_destroy(region); 2435 } 2436 2437 void 2438 fillTab(cairo_t *cr, GtkStyle *style, GtkWidget *widget, const QtcRect *area, 2439 GtkStateType state, const GdkColor *col, int x, int y, 2440 int width, int height, bool horiz, EWidget tab, bool grad) 2441 { 2442 bool selected = state == GTK_STATE_NORMAL; 2443 bool flatBgnd = !qtcIsCustomBgnd(opts) || opts.tabBgnd != 0; 2444 2445 const GdkColor *c = col; 2446 GdkColor b; 2447 double alpha = 1.0; 2448 2449 if (selected && opts.tabBgnd != 0) { 2450 qtcShade(col, &b, TO_FACTOR(opts.tabBgnd), opts.shading); 2451 c = &b; 2452 } 2453 2454 if (!selected && (opts.bgndOpacity != 100 || opts.dlgOpacity != 100)) { 2455 GtkWidget *top = widget ? gtk_widget_get_toplevel(widget) : nullptr; 2456 bool isDialog = top && GTK_IS_DIALOG(top); 2457 2458 // Note: opacity is divided by 150 to make dark inactive tabs 2459 // more translucent 2460 if (isDialog && opts.dlgOpacity != 100) { 2461 alpha = opts.dlgOpacity / 150.0; 2462 } else if (!isDialog && opts.bgndOpacity != 100) { 2463 alpha = opts.bgndOpacity / 150.0; 2464 } 2465 } 2466 2467 if (selected && opts.appearance == APPEARANCE_INVERTED) { 2468 if (flatBgnd) { 2469 Cairo::rect(cr, area, x, y, width, height, 2470 &style->bg[GTK_STATE_NORMAL], alpha); 2471 } 2472 } else if (grad) { 2473 drawBevelGradient(cr, area, x, y, width, height, c, horiz, 2474 selected, selected ? SEL_TAB_APP : NORM_TAB_APP, 2475 tab, alpha); 2476 } else if (!selected || flatBgnd) { 2477 Cairo::rect(cr, area, x, y, width, height, c, alpha); 2478 } 2479 } 2480 2481 static void 2482 colorTab(cairo_t *cr, int x, int y, int width, int height, ECornerBits round, 2483 EWidget tab, bool horiz) 2484 { 2485 cairo_pattern_t *pt = 2486 cairo_pattern_create_linear(x, y, horiz ? x : x + width - 1, 2487 horiz ? y + height - 1 : y); 2488 2489 Cairo::Saver saver(cr); 2490 qtcClipPath(cr, x, y, width, height, tab, RADIUS_EXTERNAL, round); 2491 Cairo::patternAddColorStop(pt, 0, &qtcPalette.highlight[ORIGINAL_SHADE], 2492 tab == WIDGET_TAB_TOP ? 2493 TO_ALPHA(opts.colorSelTab) : 0.0); 2494 Cairo::patternAddColorStop(pt, CAIRO_GRAD_END, 2495 &qtcPalette.highlight[ORIGINAL_SHADE], 2496 tab == WIDGET_TAB_TOP ? 0.0 : 2497 TO_ALPHA(opts.colorSelTab)); 2498 cairo_set_source(cr, pt); 2499 cairo_rectangle(cr, x, y, width, height); 2500 cairo_fill(cr); 2501 cairo_pattern_destroy(pt); 2502 } 2503 2504 void 2505 drawToolTip(cairo_t *cr, GtkWidget *widget, const QtcRect *area, 2506 int x, int y, int width, int height) 2507 { 2508 const GdkColor *col = &qtSettings.colors[PAL_ACTIVE][COLOR_TOOLTIP]; 2509 2510 bool nonGtk = isFakeGtk(); 2511 bool rounded = !nonGtk && widget && !(opts.square & SQUARE_TOOLTIPS); 2512 bool useAlpha = (!nonGtk && qtSettings.useAlpha && 2513 isRgbaWidget(widget) && compositingActive(widget)); 2514 2515 if (!nonGtk && !useAlpha && GTK_IS_WINDOW(widget)) { 2516 gtk_window_set_opacity(GTK_WINDOW(widget), 0.875); 2517 } 2518 Cairo::Saver saver(cr); 2519 if (rounded) { 2520 if (useAlpha) { 2521 cairo_rectangle(cr, x, y, width, height); 2522 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); 2523 cairo_set_source_rgba(cr, 0, 0, 0, 1); 2524 cairo_fill(cr); 2525 clearRoundedMask(widget, true); 2526 } else { 2527 createRoundedMask(widget, x, y, width, height, 2528 opts.round >= ROUND_FULL ? 5.0 : 2.5, true); 2529 } 2530 Cairo::clipWhole(cr, x, y, width, height, 2531 opts.round >= ROUND_FULL ? 5.0 : 2.5, ROUNDED_ALL); 2532 } 2533 if (useAlpha) { 2534 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); 2535 } 2536 drawBevelGradient(cr, area, x, y, width, height, col, true, false, 2537 opts.tooltipAppearance, WIDGET_TOOLTIP, 2538 useAlpha ? 0.875 : 1.0); 2539 if (!rounded && qtcIsFlat(opts.tooltipAppearance)) { 2540 cairo_new_path(cr); 2541 /*if(qtcIsFlat(opts.tooltipAppearance))*/ 2542 Cairo::setColor(cr, 2543 &qtSettings.colors[PAL_ACTIVE][COLOR_TOOLTIP_TEXT]); 2544 /*else 2545 cairo_set_source_rgba(cr, 0, 0, 0, 0.25);*/ 2546 cairo_rectangle(cr, x + 0.5, y + 0.5, width - 1, height - 1); 2547 cairo_stroke(cr); 2548 } 2549 } 2550 2551 void 2552 drawSplitter(cairo_t *cr, GtkStateType state, GtkStyle *style, 2553 const QtcRect *area, int x, int y, int width, int height) 2554 { 2555 const GdkColor *cols = 2556 (opts.coloredMouseOver && state == GTK_STATE_PRELIGHT ? 2557 qtcPalette.mouseover : qtcPalette.background); 2558 2559 if (state == GTK_STATE_PRELIGHT && opts.splitterHighlight) { 2560 GdkColor col = shadeColor(&style->bg[state], 2561 TO_FACTOR(opts.splitterHighlight)); 2562 drawSelectionGradient(cr, area, x, y, width, height, ROUNDED_ALL, 2563 false, 1.0, &col, width > height); 2564 } 2565 2566 switch (opts.splitters) { 2567 case LINE_1DOT: 2568 Cairo::dot(cr, x, y, width, height, &cols[QTC_STD_BORDER]); 2569 break; 2570 case LINE_NONE: 2571 break; 2572 case LINE_DOTS: 2573 default: 2574 Cairo::dots(cr, x, y, width, height, height > width, 2575 NUM_SPLITTER_DASHES, 1, area, 0, &cols[5], cols); 2576 break; 2577 case LINE_FLAT: 2578 case LINE_SUNKEN: 2579 case LINE_DASHES: 2580 drawLines(cr, x, y, width, height, height > width, NUM_SPLITTER_DASHES, 2581 2, cols, area, 3, opts.splitters); 2582 } 2583 } 2584 2585 void 2586 drawSidebarButton(cairo_t *cr, GtkStateType state, GtkStyle *style, 2587 const QtcRect *area, int x, int y, int width, int height) 2588 { 2589 if (oneOf(state, GTK_STATE_PRELIGHT, GTK_STATE_ACTIVE)) { 2590 bool horiz = width > height; 2591 const GdkColor *cols = (state == GTK_STATE_ACTIVE ? 2592 qtcPalette.sidebar : qtcPalette.background); 2593 drawLightBevel(cr, style, state, area, x, y, width, height, 2594 &cols[getFill(state, false)], cols, ROUNDED_NONE, 2595 WIDGET_MENU_ITEM, BORDER_FLAT, 2596 (horiz ? 0 : DF_VERT) | (state == GTK_STATE_ACTIVE ? 2597 DF_SUNKEN : 0), nullptr); 2598 2599 if (opts.coloredMouseOver && state == GTK_STATE_PRELIGHT) { 2600 const GdkColor *col = &qtcPalette.mouseover[1]; 2601 if (horiz || opts.coloredMouseOver != MO_PLASTIK) { 2602 cairo_new_path(cr); 2603 Cairo::setColor(cr, col); 2604 cairo_move_to(cr, x, y + 0.5); 2605 cairo_line_to(cr, x + width - 1, y + 0.5); 2606 cairo_move_to(cr, x + 1, y + 1.5); 2607 cairo_line_to(cr, x + width - 2, y + 1.5); 2608 cairo_stroke(cr); 2609 } 2610 if (!horiz || opts.coloredMouseOver != MO_PLASTIK) { 2611 cairo_new_path(cr); 2612 Cairo::setColor(cr, col); 2613 cairo_move_to(cr, x + 0.5, y); 2614 cairo_line_to(cr, x + 0.5, y + height - 1); 2615 cairo_move_to(cr, x + 1.5, y + 1); 2616 cairo_line_to(cr, x + 1.5, y + height - 2); 2617 cairo_stroke(cr); 2618 if (opts.coloredMouseOver != MO_PLASTIK) { 2619 col = &qtcPalette.mouseover[2]; 2620 } 2621 } 2622 if (horiz || opts.coloredMouseOver != MO_PLASTIK) { 2623 cairo_new_path(cr); 2624 Cairo::setColor(cr, col); 2625 cairo_move_to(cr, x, y + height - 1.5); 2626 cairo_line_to(cr, x + width - 1, y + height - 1.5); 2627 cairo_move_to(cr, x + 1, y + height - 2.5); 2628 cairo_line_to(cr, x + width - 2, y + height - 2.5); 2629 cairo_stroke(cr); 2630 } 2631 if (!horiz || opts.coloredMouseOver != MO_PLASTIK) { 2632 cairo_new_path(cr); 2633 Cairo::setColor(cr, col); 2634 cairo_move_to(cr, x + width - 1.5, y); 2635 cairo_line_to(cr, x + width - 1.5, y + height - 1); 2636 cairo_move_to(cr, x + width - 2.5, y + 1); 2637 cairo_line_to(cr, x + width - 2.5, y + height - 2); 2638 cairo_stroke(cr); 2639 } 2640 } 2641 } 2642 } 2643 2644 void 2645 drawMenuItem(cairo_t *cr, GtkStateType state, GtkStyle *style, 2646 GtkWidget *widget, const QtcRect *area, int x, int y, 2647 int width, int height) 2648 { 2649 GtkMenuBar *mb = isMenubar(widget, 0); 2650 #if GTK_CHECK_VERSION(2, 90, 0) /* Gtk3:TODO !!! */ 2651 bool active_mb = isFakeGtk() || gdk_pointer_is_grabbed(); 2652 #else 2653 bool active_mb = isFakeGtk() || (mb ? GTK_MENU_SHELL(mb)->active : false); 2654 2655 // The handling of 'mouse pressed' in the menubar event handler doesn't 2656 // seem to set the menu as active, therefore the active_mb fails. However 2657 // the check below works... 2658 if (mb && !active_mb && widget) 2659 active_mb = widget == GTK_MENU_SHELL(mb)->active_menu_item; 2660 #endif 2661 2662 /* The following 'if' is just a hack for a menubar item problem with 2663 pidgin. Sometime, a 12pix width 2664 empty menubar item is drawn on the right - and doesnt disappear! */ 2665 if (!mb || width > 12) { 2666 bool grayItem = ((!opts.colorMenubarMouseOver && mb && !active_mb && 2667 qtSettings.app != GTK_APP_OPEN_OFFICE) || 2668 !opts.useHighlightForMenu); 2669 const GdkColor *itemCols = (grayItem ? qtcPalette.background : 2670 qtcPalette.highlight); 2671 auto round = (mb ? active_mb && opts.roundMbTopOnly ? ROUNDED_TOP : 2672 ROUNDED_ALL : ROUNDED_ALL); 2673 auto new_state = state == GTK_STATE_PRELIGHT ? GTK_STATE_NORMAL : state; 2674 bool stdColors = (!mb || 2675 noneOf(opts.shadeMenubars, SHADE_BLEND_SELECTED, 2676 SHADE_SELECTED)); 2677 int fillVal = grayItem ? 4 : ORIGINAL_SHADE; 2678 int borderVal = opts.borderMenuitems ? 0 : fillVal; 2679 2680 if (grayItem && mb && !active_mb && !opts.colorMenubarMouseOver && 2681 (opts.borderMenuitems || !qtcIsFlat(opts.menuitemAppearance))) { 2682 fillVal = ORIGINAL_SHADE; 2683 } 2684 2685 if (mb && !opts.roundMbTopOnly && !(opts.square & SQUARE_POPUP_MENUS)) { 2686 x++; 2687 y++; 2688 width -= 2; 2689 height -= 2; 2690 } 2691 if (grayItem && !mb && 2692 (opts.lighterPopupMenuBgnd || opts.shadePopupMenu)) { 2693 itemCols = qtcPalette.menu; 2694 } 2695 if (!mb && opts.menuitemAppearance == APPEARANCE_FADE) { 2696 bool reverse = false; /* TODO !!! */ 2697 cairo_pattern_t *pt = nullptr; 2698 double fadePercent = 0.0; 2699 Cairo::Saver saver(cr); 2700 2701 if (opts.round != ROUND_NONE) { 2702 x++; 2703 y++; 2704 width -= 2; 2705 height -= 2; 2706 Cairo::clipWhole(cr, x, y, width, height, 4, 2707 reverse ? ROUNDED_RIGHT : ROUNDED_LEFT); 2708 } 2709 2710 fadePercent = ((double)MENUITEM_FADE_SIZE) / (double)width; 2711 pt = cairo_pattern_create_linear(x, y, x + width - 1, y); 2712 2713 Cairo::patternAddColorStop(pt, 0, &itemCols[fillVal], 2714 reverse ? 0.0 : 1.0); 2715 Cairo::patternAddColorStop(pt, (reverse ? fadePercent : 2716 1.0 - fadePercent), 2717 &itemCols[fillVal]); 2718 Cairo::patternAddColorStop(pt, CAIRO_GRAD_END, &itemCols[fillVal], 2719 reverse ? 1.0 : 0.0); 2720 cairo_set_source(cr, pt); 2721 cairo_rectangle(cr, x, y, width, height); 2722 cairo_fill(cr); 2723 cairo_pattern_destroy(pt); 2724 } else if (!opts.borderMenuitems && !mb) { 2725 /* For now dont round combos - getting weird effects with 2726 shadow/clipping :-( ...but these work ok if we have an rgba 2727 colormap, so in that case we dont care if its a combo...*/ 2728 bool isCombo = (!(opts.square & SQUARE_POPUP_MENUS) && widget && 2729 isComboMenu(gtk_widget_get_parent(widget)) && 2730 !(qtSettings.useAlpha && 2731 compositingActive(widget) && isRgbaWidget(widget))); 2732 bool roundedMenu = ((!widget || !isCombo) && 2733 !(opts.square & SQUARE_POPUP_MENUS)); 2734 Cairo::Saver saver(cr); 2735 2736 if (roundedMenu) { 2737 Cairo::clipWhole(cr, x, y, width, height, 2738 (opts.round >= ROUND_FULL ? 5.0 : 2.5) - 1.0, 2739 round); 2740 } 2741 drawBevelGradient(cr, area, x, y, width, height, 2742 &itemCols[fillVal], true, false, 2743 opts.menuitemAppearance, WIDGET_MENU_ITEM); 2744 } else if (stdColors && opts.borderMenuitems) { 2745 drawLightBevel(cr, style, new_state, area, x, y, 2746 width, height, &itemCols[fillVal], itemCols, 2747 round, WIDGET_MENU_ITEM, BORDER_FLAT, 2748 DF_DRAW_INSIDE | (stdColors ? DF_DO_BORDER : 0), 2749 widget); 2750 } else { 2751 if (width > 2 && height > 2) 2752 drawBevelGradient(cr, area, x + 1, y + 1, width - 2,height - 2, 2753 &itemCols[fillVal], true, false, 2754 opts.menuitemAppearance, WIDGET_MENU_ITEM); 2755 2756 drawBorder(cr, style, state, area, x, y, width, height, itemCols, 2757 round, BORDER_FLAT, WIDGET_MENU_ITEM, 0, borderVal); 2758 } 2759 } 2760 } 2761 2762 void 2763 drawMenu(cairo_t *cr, GtkWidget *widget, const QtcRect *area, 2764 int x, int y, int width, int height) 2765 { 2766 double radius = 0.0; 2767 double alpha = 1.0; 2768 bool nonGtk = isFakeGtk(); 2769 bool roundedMenu = !(opts.square & SQUARE_POPUP_MENUS) && !nonGtk; 2770 bool compsActive = compositingActive(widget); 2771 bool isAlphaWidget = compsActive && isRgbaWidget(widget); 2772 bool useAlpha = isAlphaWidget && opts.menuBgndOpacity < 100; 2773 bool useAlphaForCorners = 2774 !nonGtk && qtSettings.useAlpha && isAlphaWidget; 2775 bool comboMenu = 2776 useAlphaForCorners || !compsActive ? false : isComboMenu(widget); 2777 /* Cant round combos, unless using rgba - getting weird effects with 2778 shadow/clipping :-(. If 'useAlphaForCorners', then dont care if its a 2779 combo menu - as it can still be rounded */ 2780 2781 Cairo::Saver saver(cr); // For operator 2782 if (useAlpha) { 2783 if (widget && /*!comboMenu && */opts.menuBgndOpacity != 100) { 2784 enableBlurBehind(widget, true); 2785 } 2786 alpha = opts.menuBgndOpacity / 100.0; 2787 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); 2788 } 2789 Cairo::Saver saver2(cr); // For clipping 2790 if (roundedMenu && !comboMenu) { 2791 radius = opts.round >= ROUND_FULL ? 5.0 : 2.5; 2792 if (useAlphaForCorners) { 2793 Cairo::Saver saver(cr); 2794 cairo_rectangle(cr, x, y, width, height); 2795 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); 2796 cairo_set_source_rgba(cr, 0, 0, 0, 1); 2797 cairo_fill(cr); 2798 clearRoundedMask(widget, false); 2799 } else { 2800 createRoundedMask(widget, x, y, width, height, 2801 radius - 0.25, false); 2802 } 2803 Cairo::clipWhole(cr, x, y, width, height, radius, ROUNDED_ALL); 2804 } 2805 2806 if (!qtcIsFlatBgnd(opts.menuBgndAppearance)) { 2807 if (opts.menuBgndAppearance == APPEARANCE_STRIPED) { 2808 drawStripedBgnd(cr, x, y, width, height, 2809 &qtcPalette.menu[ORIGINAL_SHADE], alpha); 2810 } else if (opts.menuBgndAppearance == APPEARANCE_FILE) { 2811 drawBgndImage(cr, x, y, width, height, false); 2812 } else { 2813 drawBevelGradient(cr, area, x, y, width, height, 2814 &qtcPalette.menu[ORIGINAL_SHADE], 2815 opts.menuBgndGrad == GT_HORIZ, false, 2816 opts.menuBgndAppearance, WIDGET_OTHER, alpha); 2817 } 2818 } else if (opts.shadePopupMenu || opts.lighterPopupMenuBgnd || useAlpha) { 2819 Cairo::rect(cr, area, x, y, width, height, 2820 &qtcPalette.menu[ORIGINAL_SHADE], alpha); 2821 } 2822 if (opts.menuBgndImage.type != IMG_NONE) { 2823 drawBgndRings(cr, x, y, width, height, false); 2824 } 2825 if (opts.menuStripe && !comboMenu) { 2826 bool mozOo = isFakeGtk(); 2827 int stripeWidth = mozOo ? 22 : 21; 2828 2829 // To determine stripe size, we iterate over all menuitems of this menu. 2830 // If we find a GtkImageMenuItem then we can a width of 20. However, we 2831 // need to check that at least one enttry actually has an image! So, if 2832 // the first GtkImageMenuItem has an image then we're ok, otherwise we 2833 // give it a blank pixmap. 2834 if (!mozOo && widget) { 2835 GtkMenuShell *menuShell = GTK_MENU_SHELL(widget); 2836 GList *children = 2837 gtk_container_get_children(GTK_CONTAINER(menuShell)); 2838 for (GList *child = children;child;child = child->next) { 2839 if (GTK_IS_IMAGE_MENU_ITEM(child->data)) { 2840 GtkImageMenuItem *item = GTK_IMAGE_MENU_ITEM(child->data); 2841 stripeWidth = 21; 2842 if (!gtk_image_menu_item_get_image(item) || 2843 (GTK_IS_IMAGE(gtk_image_menu_item_get_image(item)) && 2844 gtk_image_get_storage_type( 2845 GTK_IMAGE(gtk_image_menu_item_get_image(item))) == 2846 GTK_IMAGE_EMPTY)) { 2847 // Give it a blank icon - so that menuStripe looks ok, 2848 // plus this matches KDE style! 2849 if (!gtk_image_menu_item_get_image(item)) { 2850 gtk_image_menu_item_set_image( 2851 item, gtk_image_new_from_pixbuf( 2852 getPixbuf(qtcPalette.check_radio, 2853 PIX_BLANK, 1.0))); 2854 } else { 2855 gtk_image_set_from_pixbuf( 2856 GTK_IMAGE(gtk_image_menu_item_get_image(item)), 2857 getPixbuf(qtcPalette.check_radio, 2858 PIX_BLANK, 1.0)); 2859 } 2860 break; 2861 } else { 2862 // TODO: Check image size! 2863 break; 2864 } 2865 } 2866 } 2867 if (children) { 2868 g_list_free(children); 2869 } 2870 } 2871 2872 drawBevelGradient(cr, area, x + 1, y + 1, stripeWidth + 1, 2873 height - 2, &opts.customMenuStripeColor, false, false, 2874 opts.menuStripeAppearance, WIDGET_OTHER, alpha); 2875 } 2876 2877 saver2.restore(); // For clipping 2878 if (opts.popupBorder) { 2879 EGradientBorder border = 2880 qtcGetGradient(opts.menuBgndAppearance, &opts)->border; 2881 cairo_new_path(cr); 2882 Cairo::setColor(cr, &qtcPalette.menu[QTC_STD_BORDER]); 2883 /* For now dont round combos - getting weird effects with 2884 * shadow/clipping :-( */ 2885 if (roundedMenu && !comboMenu) { 2886 Cairo::pathWhole(cr, x + 0.5, y + 0.5, width - 1, height - 1, 2887 radius - 1, ROUNDED_ALL); 2888 } else { 2889 cairo_rectangle(cr, x + 0.5, y + 0.5, width - 1, height - 1); 2890 } 2891 cairo_stroke(cr); 2892 if (qtcUseBorder(border) && 2893 opts.menuBgndAppearance != APPEARANCE_FLAT) { 2894 if (roundedMenu) { 2895 if (border != GB_3D) { 2896 cairo_new_path(cr); 2897 Cairo::setColor(cr, qtcPalette.menu); 2898 Cairo::pathTopLeft(cr, x + 1.5, y + 1.5, width - 3, 2899 height - 3, radius - 2, ROUNDED_ALL); 2900 cairo_stroke(cr); 2901 } 2902 cairo_new_path(cr); 2903 Cairo::setColor(cr, &qtcPalette.menu[border == GB_LIGHT ? 0 : 2904 FRAME_DARK_SHADOW]); 2905 Cairo::pathBottomRight(cr, x + 1.5, y + 1.5, width - 3, 2906 height - 3, radius - 2, ROUNDED_ALL); 2907 cairo_stroke(cr); 2908 } else { 2909 if (border != GB_3D) { 2910 Cairo::hLine(cr, x + 1, y + 1, width - 2, qtcPalette.menu); 2911 Cairo::vLine(cr, x + 1, y + 1, height - 2, 2912 qtcPalette.menu); 2913 } 2914 Cairo::hLine(cr, x + 1, y + height - 2, width - 2, 2915 &qtcPalette.menu[border == GB_LIGHT ? 0 : 2916 FRAME_DARK_SHADOW]); 2917 Cairo::vLine(cr, x + width - 2, y + 1, height - 2, 2918 &qtcPalette.menu[border == GB_LIGHT ? 0 : 2919 FRAME_DARK_SHADOW]); 2920 } 2921 } 2922 } 2923 } 2924 2925 void 2926 drawBoxGap(cairo_t *cr, GtkStyle *style, GtkShadowType shadow, 2927 GtkStateType state, GtkWidget *widget, const QtcRect *area, 2928 int x, int y, int width, int height, GtkPositionType gapSide, 2929 int gapX, int gapWidth, EBorder borderProfile, bool isTab) 2930 { 2931 if (qtSettings.debug == DEBUG_ALL) { 2932 printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %d %d %d ", __FUNCTION__, 2933 shadow, state, x, y, width, height, gapX, gapWidth, isTab); 2934 debugDisplayWidget(widget, 10); 2935 } 2936 2937 // *Very* hacky fix for tabs in thunderbird main window!!! 2938 if (isTab && isMozilla() && gapWidth == 250 && 2939 (width == 290 || width == 270) && height == 6) { 2940 return; 2941 } 2942 if (isTab && opts.tabBgnd != 0) { 2943 Cairo::Saver saver(cr); 2944 qtcClipPath(cr, x - 1, y - 1, width + 2, height + 2, 2945 WIDGET_TAB_FRAME, RADIUS_EXTERNAL, ROUNDED_ALL); 2946 drawAreaMod(cr, style, state, area, TO_FACTOR(opts.tabBgnd), 2947 x, y, width, height); 2948 } 2949 if (opts.tabMouseOver == TAB_MO_GLOW && gapWidth > 4 && 2950 isMozillaWidget(widget)) { 2951 gapWidth -= 2; 2952 } 2953 if (shadow != GTK_SHADOW_NONE) { 2954 auto round = (((!isTab && opts.square & SQUARE_FRAME) || 2955 (isTab && opts.square & SQUARE_TAB_FRAME)) ? 2956 ROUNDED_NONE : ROUNDED_ALL); 2957 GtkWidget *parent = widget ? gtk_widget_get_parent(widget) : nullptr; 2958 2959 if (!(opts.square & SQUARE_TAB_FRAME) && gapX <= 0) { 2960 switch (gapSide) { 2961 case GTK_POS_TOP: 2962 round = ECornerBits(CORNER_TR | CORNER_BL | CORNER_BR); 2963 break; 2964 case GTK_POS_BOTTOM: 2965 round = ECornerBits(CORNER_BR | CORNER_TL | CORNER_TR); 2966 break; 2967 case GTK_POS_LEFT: 2968 round = ECornerBits(CORNER_TR | CORNER_BL | CORNER_BR); 2969 break; 2970 case GTK_POS_RIGHT: 2971 round = ECornerBits(CORNER_TL | CORNER_BL | CORNER_BR); 2972 break; 2973 } 2974 } 2975 Cairo::Saver saver(cr); 2976 qtcSetGapClip(cr, area, gapSide, gapX, gapWidth, x, y, 2977 width, height, isTab); 2978 drawBorder(cr, gtk_widget_get_style(parent ? parent : widget), state, 2979 area, x, y, width, height, nullptr, round, 2980 borderProfile, isTab ? WIDGET_TAB_FRAME : WIDGET_FRAME, 2981 isTab ? 0 : DF_BLEND); 2982 } 2983 } 2984 2985 void 2986 drawBoxGapFixes(cairo_t *cr, GtkWidget *widget, int x, int y, 2987 int width, int height, GtkPositionType gapSide, int gapX, 2988 int gapWidth) 2989 { 2990 const GdkColor *col1 = &qtcPalette.background[0]; 2991 const GdkColor *col2 = 2992 &qtcPalette.background[opts.borderTab ? 0 : 2993 (opts.appearance == APPEARANCE_FLAT ? 2994 ORIGINAL_SHADE : FRAME_DARK_SHADOW)]; 2995 const GdkColor *outer = &qtcPalette.background[QTC_STD_BORDER]; 2996 bool rev = reverseLayout(widget); 2997 bool thin = opts.thin & THIN_FRAMES; 2998 int rightPos = width - (gapX + gapWidth); 2999 3000 switch (gapSide) { 3001 case GTK_POS_TOP: 3002 if (gapX > 0) { 3003 if (!thin) { 3004 Cairo::hLine(cr, x + gapX - 1, y + 1, 3, col1); 3005 Cairo::hLine(cr, x + gapX - 1, y, 3, col1); 3006 } 3007 Cairo::hLine(cr, x + gapX - 1, y, 2, outer); 3008 } else if (!thin) { 3009 Cairo::vLine(cr, x + 1, y, 2, col1); 3010 } 3011 if (rightPos >= 0) { 3012 if (!thin) { 3013 Cairo::hLine(cr, x + gapX + gapWidth - 2, y + 1, 3, col1); 3014 Cairo::vLine(cr, x + gapX + gapWidth - 2, y, 3015 rightPos ? 1 : 0, col2); 3016 } 3017 Cairo::hLine(cr, x + gapX + gapWidth - 1, y, 2, outer); 3018 } 3019 if (!(opts.square & SQUARE_TAB_FRAME) && opts.round > ROUND_SLIGHT) { 3020 if (gapX > 0 && opts.tabMouseOver == TAB_MO_GLOW) { 3021 Cairo::vLine(cr, rev ? x + width - 2 : x + 1, y, 2, outer); 3022 } else { 3023 Cairo::vLine(cr, rev ? x + width - 1 : x, y, 3, outer); 3024 if (gapX > 0 && !thin) { 3025 Cairo::hLine(cr, x + 1, y, 1, &qtcPalette.background[2]); 3026 } 3027 } 3028 } 3029 break; 3030 case GTK_POS_BOTTOM: 3031 if (gapX > 0) { 3032 if (!thin) { 3033 Cairo::hLine(cr, x + gapX - 1, y + height - 1, 2, col1); 3034 Cairo::hLine(cr, x + gapX - 1, y + height - 2, 2, col2); 3035 } 3036 Cairo::hLine(cr, x + gapX - 1, y + height - 1, 2, outer); 3037 } else if (!thin) { 3038 Cairo::vLine(cr, x + 1, y + height - 1, 2, col1); 3039 } 3040 if (rightPos >= 0) { 3041 if (!thin) { 3042 Cairo::hLine(cr, x + gapX + gapWidth - 2, 3043 y + height - 2, 3, col2); 3044 Cairo::vLine(cr, x + gapX + gapWidth - 2, 3045 y + height - 1, rightPos ? 1 : 0, col2); 3046 } 3047 Cairo::hLine(cr, x + gapX + gapWidth - 1, 3048 y + height - 1, 2, outer); 3049 } 3050 if (!(opts.square & SQUARE_TAB_FRAME) && opts.round > ROUND_SLIGHT) { 3051 if (gapX > 0 && opts.tabMouseOver == TAB_MO_GLOW) { 3052 Cairo::vLine(cr, rev ? x + width - 2 : x + 1, 3053 y + height - 2, 2, outer); 3054 } else { 3055 Cairo::vLine(cr, rev ? x + width - 1 : x, 3056 y + height - 3, 3, outer); 3057 } 3058 } 3059 break; 3060 case GTK_POS_LEFT: 3061 if (gapX > 0) { 3062 if (!thin) { 3063 Cairo::vLine(cr, x + 1, y + gapX - 1, 3, col1); 3064 Cairo::vLine(cr, x, y + gapX - 1, 3, col1); 3065 } 3066 Cairo::vLine(cr, x, y + gapX - 1, 2, outer); 3067 } else if (!thin) { 3068 Cairo::hLine(cr, x, y + 1, 2, col1); 3069 } 3070 if (height - (gapX + gapWidth) > 0) { 3071 if (!thin) { 3072 Cairo::vLine(cr, x + 1, y + gapX + gapWidth - 2, 3, col1); 3073 Cairo::vLine(cr, x, y + gapX + gapWidth - 2, 1, col2); 3074 } 3075 Cairo::vLine(cr, x, y + gapX + gapWidth - 1, 2, outer); 3076 } 3077 if(!(opts.square & SQUARE_TAB_FRAME) && opts.round > ROUND_SLIGHT) { 3078 if (gapX > 0 && opts.tabMouseOver == TAB_MO_GLOW) { 3079 Cairo::hLine(cr, x, y + 1, 2, outer); 3080 } else { 3081 Cairo::hLine(cr, x, y, 3, outer); 3082 if (gapX > 0 && !thin) { 3083 Cairo::hLine(cr, x, y + 1, 1, &qtcPalette.background[2]); 3084 } 3085 } 3086 } 3087 break; 3088 case GTK_POS_RIGHT: 3089 if (gapX > 0) { 3090 if (!thin) 3091 Cairo::vLine(cr, x + width - 2, y + gapX - 1, 2, col2); 3092 Cairo::vLine(cr, x + width - 1, y + gapX - 1, 2, outer); 3093 } else if (!thin) { 3094 Cairo::hLine(cr, x + width - 2, y + 1, 3, col1); 3095 } 3096 3097 if (height - (gapX + gapWidth) > 0) { 3098 if (!thin) { 3099 Cairo::hLine(cr, x + width - 2, 3100 y + gapX + gapWidth - 2, 3, col2); 3101 Cairo::vLine(cr, x + width - 2, 3102 y + gapX + gapWidth - 1, 2, col2); 3103 } 3104 Cairo::vLine(cr, x + width - 1, y + gapX + gapWidth - 1, 2, outer); 3105 } 3106 if (!(opts.square & SQUARE_TAB_FRAME) && opts.round > ROUND_SLIGHT) { 3107 if (gapX > 0 && opts.tabMouseOver == TAB_MO_GLOW) { 3108 Cairo::hLine(cr, x + width - 2, y + 1, 2, outer); 3109 } else { 3110 Cairo::hLine(cr, x + width - 3, y, 3, outer); 3111 } 3112 } 3113 break; 3114 } 3115 } 3116 3117 void 3118 drawShadowGap(cairo_t *cr, GtkStyle *style, GtkShadowType shadow, 3119 GtkStateType state, GtkWidget *widget, const QtcRect *area, 3120 int x, int y, int width, int height, GtkPositionType gapSide, 3121 int gapX, int gapWidth) 3122 { 3123 bool drawFrame = true; 3124 bool isGroupBox = IS_GROUP_BOX(widget); 3125 3126 if (isGroupBox) { 3127 if (gapX < 5) { 3128 gapX += 5; 3129 gapWidth += 2; 3130 } 3131 switch (opts.groupBox) { 3132 case FRAME_NONE: 3133 drawFrame = false; 3134 return; 3135 case FRAME_LINE: 3136 case FRAME_SHADED: 3137 case FRAME_FADED: 3138 if (opts.gbLabel & (GB_LBL_INSIDE | GB_LBL_OUTSIDE) && widget && 3139 GTK_IS_FRAME(widget)) { 3140 GtkFrame *frame = GTK_FRAME(widget); 3141 GtkRequisition child_requisition; 3142 int height_extra; 3143 GtkStyle *style = 3144 (frame ? gtk_widget_get_style(GTK_WIDGET(frame)) : nullptr); 3145 GtkWidget *label = 3146 (frame ? gtk_frame_get_label_widget(frame) : nullptr); 3147 3148 if (style && label) { 3149 gtk_widget_get_child_requisition(label, &child_requisition); 3150 height_extra = 3151 (qtcMax(0, child_requisition.height - 3152 style->ythickness) - 3153 qtcFrameGetLabelYAlign(frame) * 3154 child_requisition.height) + 2; 3155 3156 if (opts.gbLabel & GB_LBL_INSIDE) { 3157 y -= height_extra; 3158 height += height_extra; 3159 gapWidth = 0; 3160 } else if (opts.gbLabel & GB_LBL_OUTSIDE) { 3161 y += height_extra; 3162 height -= height_extra; 3163 gapWidth = 0; 3164 } 3165 } 3166 } 3167 if (opts.groupBox == FRAME_LINE) { 3168 QtcRect gap = {x, y, gapWidth, 1}; 3169 drawFadedLine(cr, x, y, width, 1, 3170 &qtcPalette.background[QTC_STD_BORDER], 3171 area, gapWidth > 0 ? &gap : nullptr, 3172 false, true, true); 3173 drawFrame = false; 3174 } else if (shadow != GTK_SHADOW_NONE) { 3175 auto round = (opts.square & SQUARE_FRAME ? 3176 ROUNDED_NONE : ROUNDED_ALL); 3177 double col = opts.gbFactor < 0 ? 0.0 : 1.0; 3178 double radius = 3179 (round == ROUNDED_ALL ? 3180 qtcGetRadius(&opts, width, height, WIDGET_FRAME, 3181 RADIUS_EXTERNAL) : 0.0); 3182 if (opts.gbFactor != 0) { 3183 Cairo::Saver saver(cr); 3184 Cairo::clipWhole(cr, x + 0.5, y + 0.5, width - 1, 3185 height - 1, radius, round); 3186 cairo_rectangle(cr, x, y, width, height); 3187 if (opts.groupBox == FRAME_SHADED) { 3188 cairo_set_source_rgba(cr, col, col, col, 3189 TO_ALPHA(opts.gbFactor)); 3190 } else { 3191 cairo_pattern_t *pt = 3192 cairo_pattern_create_linear(x, y, x, 3193 y + height - 1); 3194 cairo_pattern_add_color_stop_rgba( 3195 pt, 0, col, col, col, TO_ALPHA(opts.gbFactor)); 3196 cairo_pattern_add_color_stop_rgba( 3197 pt, CAIRO_GRAD_END, col, col, col, 0); 3198 cairo_set_source(cr, pt); 3199 cairo_pattern_destroy(pt); 3200 } 3201 cairo_fill(cr); 3202 } 3203 if (opts.groupBox == FRAME_FADED) { 3204 cairo_pattern_t *pt = 3205 cairo_pattern_create_linear(x, y, x, y + height - 1); 3206 Cairo::patternAddColorStop( 3207 pt, 0, &qtcPalette.background[QTC_STD_BORDER]); 3208 Cairo::patternAddColorStop( 3209 pt, CAIRO_GRAD_END, 3210 &qtcPalette.background[QTC_STD_BORDER], 0); 3211 Cairo::Saver saver(cr); 3212 qtcSetGapClip(cr, area, gapSide, gapX, gapWidth, 3213 x, y, width, height, false); 3214 cairo_set_source(cr, pt); 3215 Cairo::pathWhole(cr, x + 0.5, y + 0.5, width - 1, 3216 height - 1, radius, round); 3217 cairo_stroke(cr); 3218 cairo_pattern_destroy(pt); 3219 drawFrame = false; 3220 } 3221 } 3222 break; 3223 default: 3224 break; 3225 } 3226 } 3227 if (drawFrame) { 3228 drawBoxGap(cr, style, shadow, state, widget, area, x, y, 3229 width, height, gapSide, gapX, gapWidth, 3230 isGroupBox && opts.groupBox == FRAME_SHADED && 3231 shadow != GTK_SHADOW_NONE ? BORDER_SUNKEN : 3232 shadowToBorder(shadow), false); 3233 } 3234 } 3235 3236 void 3237 drawCheckBox(cairo_t *cr, GtkStateType state, GtkShadowType shadow, 3238 GtkStyle *style, GtkWidget *widget, const char *detail, 3239 const QtcRect *area, int x, int y, int width, int height) 3240 { 3241 if (state == GTK_STATE_PRELIGHT && 3242 oneOf(qtSettings.app, GTK_APP_MOZILLA, GTK_APP_JAVA)) { 3243 state = GTK_STATE_NORMAL; 3244 } 3245 bool mnu = oneOf(detail, "check"); 3246 bool list = !mnu && isList(widget); 3247 bool on = shadow == GTK_SHADOW_IN; 3248 bool tri = shadow == GTK_SHADOW_ETCHED_IN; 3249 bool doEtch = opts.buttonEffect != EFFECT_NONE; 3250 GdkColor newColors[TOTAL_SHADES + 1]; 3251 const GdkColor *btnColors; 3252 auto ind_state = ((list || (!mnu && state == GTK_STATE_INSENSITIVE)) ? 3253 state : GTK_STATE_NORMAL); 3254 int checkSpace = doEtch ? opts.crSize + 2 : opts.crSize; 3255 3256 if (opts.crColor && state != GTK_STATE_INSENSITIVE && (on || tri)) { 3257 btnColors = qtcPalette.selectedcr; 3258 } else if (!mnu && !list && QT_CUSTOM_COLOR_BUTTON(style)) { 3259 shadeColors(&style->bg[state], newColors); 3260 btnColors = newColors; 3261 } else { 3262 btnColors = qtcPalette.button[state == GTK_STATE_INSENSITIVE ? 3263 PAL_DISABLED : PAL_ACTIVE]; 3264 } 3265 x += (width - checkSpace) / 2; 3266 y += (height - checkSpace) / 2; 3267 if (qtSettings.debug == DEBUG_ALL) { 3268 printf(DEBUG_PREFIX "%s %d %d %d %d %d %d %d %s ", 3269 __FUNCTION__, state, shadow, x, y, width, height, mnu, 3270 detail ? detail : "nullptr"); 3271 debugDisplayWidget(widget, 10); 3272 } 3273 if ((mnu && state == GTK_STATE_PRELIGHT) || 3274 (list && state == GTK_STATE_ACTIVE)) { 3275 state = GTK_STATE_NORMAL; 3276 } 3277 if (mnu && isMozilla()) { 3278 x -= 2; 3279 } 3280 if (!mnu || qtSettings.qt4) { 3281 if (opts.crButton) { 3282 drawLightBevel(cr, style, state, area, x, y, checkSpace, 3283 checkSpace, &btnColors[getFill(state, false)], 3284 btnColors, ROUNDED_ALL, WIDGET_CHECKBOX, BORDER_FLAT, 3285 DF_DO_BORDER | 3286 (state == GTK_STATE_ACTIVE ? DF_SUNKEN : 0), 3287 list ? nullptr : widget); 3288 if (doEtch) { 3289 x++; 3290 y++; 3291 } 3292 } else { 3293 bool coloredMouseOver = 3294 state == GTK_STATE_PRELIGHT && opts.coloredMouseOver; 3295 bool glow = (doEtch && state == GTK_STATE_PRELIGHT && 3296 opts.coloredMouseOver == MO_GLOW); 3297 bool lightBorder = DRAW_LIGHT_BORDER(false, WIDGET_TROUGH, 3298 APPEARANCE_INVERTED); 3299 const GdkColor *colors = 3300 coloredMouseOver ? qtcPalette.mouseover : btnColors; 3301 const GdkColor *bgndCol = 3302 (oneOf(state, GTK_STATE_INSENSITIVE, GTK_STATE_ACTIVE) ? 3303 &style->bg[GTK_STATE_NORMAL] : 3304 !mnu && state == GTK_STATE_PRELIGHT && !coloredMouseOver && 3305 !opts.crHighlight ? &btnColors[CR_MO_FILL] : 3306 &style->base[GTK_STATE_NORMAL]); 3307 if (doEtch) { 3308 x++; 3309 y++; 3310 } 3311 3312 drawBevelGradient(cr, area, x + 1, y + 1, opts.crSize - 2, 3313 opts.crSize - 2, bgndCol, true, false, 3314 APPEARANCE_INVERTED, WIDGET_TROUGH); 3315 3316 if (coloredMouseOver && !glow) { 3317 cairo_new_path(cr); 3318 Cairo::setColor(cr, &colors[CR_MO_FILL]); 3319 cairo_rectangle(cr, x + 1.5, y + 1.5, opts.crSize - 3, 3320 opts.crSize - 3); 3321 /* cairo_rectangle(cr, x + 2.5, y + 2.5, opts.crSize - 5, */ 3322 /* opts.crSize - 5); */ 3323 cairo_stroke(cr); 3324 } else { 3325 cairo_new_path(cr); 3326 if (lightBorder) { 3327 Cairo::setColor( 3328 cr, &btnColors[LIGHT_BORDER(APPEARANCE_INVERTED)]); 3329 cairo_rectangle(cr, x + 1.5, y + 1.5, opts.crSize - 3, 3330 opts.crSize - 3); 3331 } else { 3332 GdkColor mid = midColor(state == GTK_STATE_INSENSITIVE ? 3333 &style->bg[GTK_STATE_NORMAL] : 3334 &style->base[GTK_STATE_NORMAL], 3335 &colors[3]); 3336 Cairo::setColor(cr, &mid); 3337 cairo_move_to(cr, x + 1.5, y + opts.crSize - 1.5); 3338 cairo_line_to(cr, x + 1.5, y + 1.5); 3339 cairo_line_to(cr, x + opts.crSize - 1.5, y + 1.5); 3340 } 3341 cairo_stroke(cr); 3342 } 3343 if (doEtch && (!list || glow) && !mnu) { 3344 if(glow && !(opts.thin & THIN_FRAMES)) { 3345 drawGlow(cr, area, x - 1, y - 1, opts.crSize + 2, 3346 opts.crSize + 2, ROUNDED_ALL, WIDGET_CHECKBOX); 3347 } else { 3348 drawEtch(cr, area, widget, x - 1, y - 1, 3349 opts.crSize + 2, opts.crSize + 2, false, 3350 ROUNDED_ALL, WIDGET_CHECKBOX); 3351 } 3352 } 3353 drawBorder(cr, style, state, area, x, y, opts.crSize, 3354 opts.crSize, colors, ROUNDED_ALL, BORDER_FLAT, 3355 WIDGET_CHECKBOX, 0); 3356 } 3357 } 3358 3359 if (on) { 3360 GdkPixbuf *pix = getPixbuf(getCheckRadioCol(style, ind_state, mnu), 3361 PIX_CHECK, 1.0); 3362 int pw = gdk_pixbuf_get_width(pix); 3363 int ph = gdk_pixbuf_get_height(pix); 3364 int dx = x + opts.crSize / 2 - pw / 2; 3365 int dy = y + opts.crSize / 2 - ph/2; 3366 3367 gdk_cairo_set_source_pixbuf(cr, pix, dx, dy); 3368 cairo_paint(cr); 3369 } else if (tri) { 3370 int ty = y + opts.crSize / 2; 3371 const GdkColor *col = getCheckRadioCol(style, ind_state, mnu); 3372 3373 Cairo::hLine(cr, x + 3, ty, opts.crSize - 6, col); 3374 Cairo::hLine(cr, x + 3, ty + 1, opts.crSize - 6, col); 3375 } 3376 } 3377 3378 void 3379 drawRadioButton(cairo_t *cr, GtkStateType state, GtkShadowType shadow, 3380 GtkStyle *style, GtkWidget *widget, const char *detail, 3381 const QtcRect *area, int x, int y, int width, int height) 3382 { 3383 if (state == GTK_STATE_PRELIGHT && 3384 oneOf(qtSettings.app, GTK_APP_MOZILLA, GTK_APP_JAVA)) { 3385 state = GTK_STATE_NORMAL; 3386 } 3387 bool mnu = oneOf(detail, "option"); 3388 bool list = !mnu && isList(widget); 3389 if ((mnu && state == GTK_STATE_PRELIGHT) || 3390 (list && state == GTK_STATE_ACTIVE)) { 3391 state = GTK_STATE_NORMAL; 3392 } 3393 3394 if (!qtSettings.qt4 && mnu) { 3395 drawCheckBox(cr, state, shadow, style, widget, "check", area, 3396 x, y, width, height); 3397 } else { 3398 bool on = shadow == GTK_SHADOW_IN; 3399 bool tri = shadow == GTK_SHADOW_ETCHED_IN; 3400 bool doEtch = opts.buttonEffect != EFFECT_NONE; 3401 auto ind_state = (state == GTK_STATE_INSENSITIVE ? 3402 state : GTK_STATE_NORMAL); 3403 int optSpace = doEtch ? opts.crSize + 2 : opts.crSize; 3404 GdkColor newColors[TOTAL_SHADES + 1]; 3405 const GdkColor *btnColors; 3406 x += (width - optSpace) / 2; 3407 y += (height - optSpace) / 2; 3408 if (opts.crColor && state != GTK_STATE_INSENSITIVE && (on || tri)) { 3409 btnColors = qtcPalette.selectedcr; 3410 } else if (!mnu && !list && QT_CUSTOM_COLOR_BUTTON(style)) { 3411 shadeColors(&style->bg[state], newColors); 3412 btnColors = newColors; 3413 } else { 3414 btnColors = qtcPalette.button[state == GTK_STATE_INSENSITIVE ? 3415 PAL_DISABLED : PAL_ACTIVE]; 3416 } 3417 if (opts.crButton) { 3418 drawLightBevel(cr, style, state, area, x, y, optSpace, 3419 optSpace, &btnColors[getFill(state, false)], 3420 btnColors, ROUNDED_ALL, WIDGET_RADIO_BUTTON, 3421 BORDER_FLAT, DF_DO_BORDER | 3422 (state == GTK_STATE_ACTIVE ? DF_SUNKEN : 0), 3423 list ? nullptr : widget); 3424 if (doEtch) { 3425 x++; 3426 y++; 3427 } 3428 } else { 3429 bool glow = (doEtch && state == GTK_STATE_PRELIGHT && 3430 opts.coloredMouseOver == MO_GLOW); 3431 bool lightBorder = DRAW_LIGHT_BORDER(false, WIDGET_TROUGH, 3432 APPEARANCE_INVERTED); 3433 bool coloredMouseOver = (state == GTK_STATE_PRELIGHT && 3434 opts.coloredMouseOver); 3435 bool doneShadow = false; 3436 const GdkColor *colors = (coloredMouseOver ? 3437 qtcPalette.mouseover : btnColors); 3438 const GdkColor *bgndCol = 3439 (oneOf(state, GTK_STATE_INSENSITIVE, GTK_STATE_ACTIVE) ? 3440 &style->bg[GTK_STATE_NORMAL] : 3441 !mnu && GTK_STATE_PRELIGHT == state && 3442 !coloredMouseOver && !opts.crHighlight ? 3443 &colors[CR_MO_FILL] : &style->base[GTK_STATE_NORMAL]); 3444 double radius = (opts.crSize + 1) / 2.0; 3445 3446 if (doEtch) { 3447 x++; 3448 y++; 3449 } 3450 cairo_save(cr); 3451 qtcClipPath(cr, x, y, opts.crSize, opts.crSize, 3452 WIDGET_RADIO_BUTTON, RADIUS_EXTERNAL, ROUNDED_ALL); 3453 drawBevelGradient(cr, nullptr, x + 1, y + 1, opts.crSize - 2, 3454 opts.crSize - 2, bgndCol,true, false, 3455 APPEARANCE_INVERTED, WIDGET_TROUGH); 3456 cairo_restore(cr); 3457 if (!mnu && coloredMouseOver && !glow) { 3458 double radius = (opts.crSize - 2) / 2.0; 3459 Cairo::setColor(cr, &colors[CR_MO_FILL]); 3460 cairo_arc(cr, x + radius + 1, y+radius + 1, 3461 radius, 0, 2 * M_PI); 3462 cairo_stroke(cr); 3463 radius--; 3464 cairo_arc(cr, x + radius + 2, y + radius + 2, 3465 radius, 0, 2 * M_PI); 3466 cairo_stroke(cr); 3467 } 3468 if (!doneShadow && doEtch && !mnu && (!list || glow)) { 3469 double radius = (opts.crSize + 1) / 2.0; 3470 if (glow) { 3471 Cairo::setColor(cr, &qtcPalette.mouseover[GLOW_MO]); 3472 } else { 3473 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 3474 ETCH_RADIO_TOP_ALPHA); 3475 } 3476 if (opts.buttonEffect != EFFECT_NONE || glow) { 3477 cairo_arc(cr, x + radius - 0.5, y + radius - 0.5, 3478 radius, 0.75 * M_PI, 1.75 * M_PI); 3479 cairo_stroke(cr); 3480 if (!glow) { 3481 setLowerEtchCol(cr, widget); 3482 } 3483 } 3484 cairo_arc(cr, x + radius - 0.5, y + radius - 0.5, 3485 radius, 1.75 * M_PI, 0.75 * M_PI); 3486 cairo_stroke(cr); 3487 } 3488 Cairo::setColor( 3489 cr, &colors[coloredMouseOver ? 4 : 3490 BORDER_VAL(state != GTK_STATE_INSENSITIVE)]); 3491 radius = (opts.crSize - 0.5)/2.0; 3492 cairo_arc(cr, x + 0.25 + radius, y + 0.25 + radius, 3493 radius, 0, 2 * M_PI); 3494 cairo_stroke(cr); 3495 if (!coloredMouseOver) { 3496 radius = (opts.crSize - 1) / 2.0; 3497 Cairo::setColor(cr, &btnColors[coloredMouseOver ? 3 : 4]); 3498 cairo_arc(cr, x + 0.75 + radius, y + 0.75 + radius, radius, 3499 lightBorder ? 0 : 0.75 * M_PI, 3500 lightBorder ? 2 * M_PI : 1.75 * M_PI); 3501 cairo_stroke(cr); 3502 } 3503 } 3504 if (on) { 3505 const GdkColor *col = getCheckRadioCol(style, ind_state, mnu); 3506 double radius = opts.smallRadio ? 2.5 : 3.5; 3507 double offset = opts.crSize / 2.0 - radius; 3508 3509 Cairo::setColor(cr, col); 3510 cairo_arc(cr, x + offset + radius, y + offset + radius, 3511 radius, 0, 2 * M_PI); 3512 cairo_fill(cr); 3513 } else if (tri) { 3514 int ty = y + opts.crSize / 2; 3515 const GdkColor *col = getCheckRadioCol(style, ind_state, mnu); 3516 3517 Cairo::hLine(cr, x + 3, ty, opts.crSize - 6, col); 3518 Cairo::hLine(cr, x + 3, ty + 1, opts.crSize - 6, col); 3519 } 3520 } 3521 } 3522 3523 void 3524 drawTab(cairo_t *cr, GtkStateType state, GtkStyle *style, GtkWidget *widget, 3525 QtcRect *area, int x, int y, int width, int height, 3526 GtkPositionType gapSide) 3527 { 3528 GtkNotebook *notebook = 3529 GTK_IS_NOTEBOOK(widget) ? GTK_NOTEBOOK(widget) : nullptr; 3530 bool highlightingEnabled = notebook && (opts.highlightFactor || 3531 opts.coloredMouseOver); 3532 bool highlight = false; 3533 int highlightedTabIndex = Tab::currentHoveredIndex(widget); 3534 int moOffset = ((opts.round == ROUND_NONE || 3535 opts.tabMouseOver != TAB_MO_TOP) ? 1 : opts.round); 3536 GtkWidget *parent = widget ? gtk_widget_get_parent(widget) : nullptr; 3537 bool firstTab = !notebook; 3538 bool lastTab = !notebook; 3539 bool vertical = oneOf(gapSide, GTK_POS_LEFT, GTK_POS_RIGHT); 3540 bool active = state == GTK_STATE_NORMAL; /* Normal -> active tab? */ 3541 bool rev = (oneOf(gapSide, GTK_POS_TOP, GTK_POS_BOTTOM) && parent && 3542 reverseLayout(parent)); 3543 bool mozTab = isMozillaTab(widget); 3544 bool glowMo = (!active && notebook && opts.coloredMouseOver && 3545 opts.tabMouseOver == TAB_MO_GLOW); 3546 bool drawOuterGlow = glowMo && !(opts.thin & THIN_FRAMES); 3547 int mod = active ? 1 : 0; 3548 int highlightOffset = (opts.highlightTab && 3549 opts.round > ROUND_SLIGHT ? 2 : 1); 3550 int highlightBorder = opts.round > ROUND_FULL ? 4 : 3; 3551 int sizeAdjust = ((!active || mozTab) && 3552 opts.tabMouseOver == TAB_MO_GLOW ? 1 : 0); 3553 int tabIndex = -1; 3554 const GdkColor *col = (active ? &style->bg[GTK_STATE_NORMAL] : 3555 &qtcPalette.background[2]); 3556 const GdkColor *selCol1 = &qtcPalette.highlight[0]; 3557 QtcRect clipArea; 3558 EBorder borderProfile = (active || opts.borderInactiveTab ? opts.borderTab ? 3559 BORDER_LIGHT : BORDER_RAISED : BORDER_FLAT); 3560 3561 #if !GTK_CHECK_VERSION(2, 90, 0) 3562 /* Hacky fix for tabs in Thunderbird */ 3563 if (mozTab && area && area->x < x - 10) { 3564 return; 3565 } 3566 #endif 3567 3568 /* f'in mozilla apps dont really use Gtk widgets - they just paint to a 3569 pixmap. So, no way of knowing the position of a tab! The 'best' look 3570 seems to be to round both corners. Not nice, but... */ 3571 if (mozTab || qtSettings.app == GTK_APP_JAVA) { 3572 firstTab = lastTab = true; 3573 } else if (notebook) { 3574 /* Borrowed from Qt engine... */ 3575 GList *children = gtk_container_get_children(GTK_CONTAINER(widget)); 3576 int num_children = children ? g_list_length(children) : 0; 3577 int sdiff = 10000; 3578 int first_shown = -1; 3579 int last_shown = -1; 3580 if (children) { 3581 g_list_free(children); 3582 } 3583 for (int i = 0; i < num_children;i++) { 3584 GtkWidget *page = gtk_notebook_get_nth_page(notebook, i); 3585 GtkWidget *tab_label = gtk_notebook_get_tab_label(notebook, page); 3586 int diff = -1; 3587 3588 if (tab_label) { 3589 QtcRect alloc = Widget::getAllocation(tab_label); 3590 diff = vertical ? alloc.y - y : alloc.x - x; 3591 } 3592 3593 if (diff > 0 && diff < sdiff) { 3594 sdiff = diff; 3595 tabIndex = i; 3596 } 3597 3598 if (page && gtk_widget_get_visible(page)) { 3599 if (i > last_shown) { 3600 last_shown = i; 3601 } 3602 if (first_shown == -1) { 3603 first_shown = i; 3604 } 3605 } 3606 } 3607 3608 if (oneOf(tabIndex, 0, first_shown)) { 3609 firstTab = true; 3610 } else if (oneOf(tabIndex, num_children - 1, last_shown)) { 3611 lastTab = true; 3612 } 3613 if (noneOf(highlightedTabIndex, -1, tabIndex) && !active) { 3614 highlight = true; 3615 col = &qtcPalette.background[SHADE_2_HIGHLIGHT]; 3616 } 3617 } 3618 3619 if (rev) { 3620 bool oldLast = lastTab; 3621 3622 lastTab = firstTab; 3623 firstTab = oldLast; 3624 } 3625 3626 if (!mozTab && qtSettings.app != GTK_APP_JAVA) { 3627 if (highlightedTabIndex == -1 && 3628 (highlightingEnabled || opts.windowDrag >= WM_DRAG_ALL)) { 3629 Tab::setup(widget); 3630 } 3631 Tab::updateRect(widget, tabIndex, x, y, width, height); 3632 } 3633 3634 /* 3635 gtk_style_apply_default_background(style, window, widget && !qtcWidgetNoWindow(widget), 3636 GTK_STATE_NORMAL, area, x, y, width, height); 3637 */ 3638 /* 3639 TODO: This is not good, should respect 'area' as passed in. However, 3640 it works for the moment - if the thunderbird hack above is used. 3641 Needs to be fixed tho. 3642 */ 3643 3644 /* In addition to the above, doing this section only for the active mozilla 3645 tab seems to fix some drawing errors with firefox3...*/ 3646 /* CPD 28/02/2008 Dont need to do any of this for firefox 3beta4 */ 3647 if (!mozTab) { 3648 clipArea = qtcRect(x, y, width, height); 3649 area = &clipArea; 3650 } 3651 3652 glowMo = glowMo && highlight; 3653 drawOuterGlow = drawOuterGlow && highlight; 3654 3655 switch (gapSide) { 3656 case GTK_POS_TOP: { 3657 /* tabs are on bottom !!! */ 3658 auto round = (active || (firstTab && lastTab) || 3659 opts.tabMouseOver == TAB_MO_GLOW || 3660 opts.roundAllTabs ? ROUNDED_BOTTOM : 3661 firstTab ? ROUNDED_BOTTOMLEFT : lastTab ? 3662 ROUNDED_BOTTOMRIGHT : ROUNDED_NONE); 3663 cairo_save(cr); 3664 qtcClipPath(cr, x, y - 4, width, height + 4, WIDGET_TAB_BOT, 3665 RADIUS_EXTERNAL, round); 3666 fillTab(cr, style, widget, area, state, col, 3667 x + mod + sizeAdjust, y, width - (2 * mod + sizeAdjust), 3668 height - 1, true, WIDGET_TAB_BOT, notebook != nullptr); 3669 cairo_restore(cr); 3670 drawBorder(cr, style, state, area, x + sizeAdjust, y - 4, 3671 width - 2 * sizeAdjust, height + 4, 3672 glowMo ? qtcPalette.mouseover : qtcPalette.background, 3673 round, borderProfile, WIDGET_TAB_BOT, 0); 3674 if (drawOuterGlow) { 3675 if (area) { 3676 area->height++; 3677 } 3678 drawGlow(cr, area, x, y - 4, width, height + 5, 3679 round, WIDGET_OTHER); 3680 } 3681 3682 if (notebook && opts.highlightTab && active) { 3683 Cairo::hLine(cr, x + 1, y + height - 3, width - 2, selCol1, 0.5); 3684 Cairo::hLine(cr, x + highlightOffset, y + height - 2, 3685 width - 2 * highlightOffset, selCol1); 3686 3687 clipArea.y = y + height - highlightBorder; 3688 clipArea.height = highlightBorder; 3689 drawBorder(cr, style, state, &clipArea, x, y, 3690 width, height, qtcPalette.highlight, ROUNDED_BOTTOM, 3691 BORDER_FLAT, WIDGET_OTHER, 0, 3); 3692 } 3693 3694 if (opts.colorSelTab && notebook && active) 3695 colorTab(cr, x + mod + sizeAdjust, y, 3696 width - (2 * mod + sizeAdjust), height - 1, round, 3697 WIDGET_TAB_BOT, true); 3698 3699 if (notebook && opts.coloredMouseOver && highlight && 3700 opts.tabMouseOver != TAB_MO_GLOW) 3701 drawHighlight(cr, x + (firstTab ? moOffset : 1), 3702 y + (opts.tabMouseOver == TAB_MO_TOP ? 3703 height - 2 : -1), 3704 width - (firstTab || lastTab ? moOffset : 1), 2, 3705 nullptr, true, opts.tabMouseOver != TAB_MO_TOP); 3706 break; 3707 } 3708 case GTK_POS_BOTTOM: { 3709 /* tabs are on top !!! */ 3710 auto round = (active || (firstTab && lastTab) || 3711 opts.tabMouseOver == TAB_MO_GLOW || 3712 opts.roundAllTabs ? ROUNDED_TOP : 3713 firstTab ? ROUNDED_TOPLEFT : lastTab ? 3714 ROUNDED_TOPRIGHT : ROUNDED_NONE); 3715 cairo_save(cr); 3716 qtcClipPath(cr, x + mod + sizeAdjust, y, 3717 width - 2 * (mod + (mozTab ? 2 * sizeAdjust : sizeAdjust)), 3718 height + 5, WIDGET_TAB_TOP, RADIUS_EXTERNAL, round); 3719 fillTab(cr, style, widget, area, state, col, 3720 x + mod + sizeAdjust, y + 1, 3721 width - 2 * (mod + (mozTab ? 2 * sizeAdjust : sizeAdjust)), 3722 height - 1, true, WIDGET_TAB_TOP,notebook != nullptr); 3723 cairo_restore(cr); 3724 drawBorder(cr, style, state, area, x + sizeAdjust, y, 3725 width - 2 * (mozTab ? 2 : 1) * sizeAdjust, height + 4, 3726 glowMo ? qtcPalette.mouseover : qtcPalette.background, 3727 round, borderProfile, WIDGET_TAB_TOP, 0); 3728 if (drawOuterGlow) { 3729 if (area) { 3730 area->y--; 3731 area->height += 2; 3732 } 3733 drawGlow(cr, area, x, y - 1, width, height + 5, 3734 round, WIDGET_OTHER); 3735 } 3736 3737 if (notebook && opts.highlightTab && active) { 3738 Cairo::hLine(cr, x + 1, y + 2, width - 2, selCol1, 0.5); 3739 Cairo::hLine(cr, x + highlightOffset, y + 1, 3740 width - 2 * highlightOffset, selCol1); 3741 3742 clipArea.y = y; 3743 clipArea.height = highlightBorder; 3744 drawBorder(cr, style, state, &clipArea, x, y, width, height, 3745 qtcPalette.highlight, ROUNDED_TOP, BORDER_FLAT, 3746 WIDGET_OTHER, 0, 3); 3747 } 3748 3749 if (opts.colorSelTab && notebook && active) 3750 colorTab(cr, x + mod + sizeAdjust, y + 1, 3751 width - 2 * (mod + (mozTab ? 2 * sizeAdjust : sizeAdjust)), 3752 height - 1, round, WIDGET_TAB_TOP, true); 3753 3754 if (notebook && opts.coloredMouseOver && highlight && 3755 opts.tabMouseOver != TAB_MO_GLOW) { 3756 drawHighlight(cr, x + (firstTab ? moOffset : 1), 3757 y + (opts.tabMouseOver == TAB_MO_TOP ? 3758 0 : height - 1), 3759 width - (firstTab || lastTab ? moOffset : 1), 3760 2, nullptr, true, opts.tabMouseOver == TAB_MO_TOP); 3761 } 3762 break; 3763 } 3764 case GTK_POS_LEFT: { 3765 /* tabs are on right !!! */ 3766 auto round = (active || (firstTab && lastTab) || 3767 opts.tabMouseOver == TAB_MO_GLOW || 3768 opts.roundAllTabs ? ROUNDED_RIGHT : 3769 firstTab ? ROUNDED_TOPRIGHT : lastTab ? 3770 ROUNDED_BOTTOMRIGHT : ROUNDED_NONE); 3771 cairo_save(cr); 3772 qtcClipPath(cr, x - 4, y, width + 4, height, WIDGET_TAB_BOT, 3773 RADIUS_EXTERNAL, round); 3774 fillTab(cr, style, widget, area, state, col, x, 3775 y + mod + sizeAdjust, width - 1, 3776 height - 2 * (mod + sizeAdjust), false, 3777 WIDGET_TAB_BOT, notebook != nullptr); 3778 cairo_restore(cr); 3779 drawBorder(cr, style, state, area, x - 4, y + sizeAdjust, 3780 width + 4, height - 2 * sizeAdjust, 3781 glowMo ? qtcPalette.mouseover : qtcPalette.background, 3782 round, borderProfile, WIDGET_TAB_BOT, 0); 3783 if (drawOuterGlow) { 3784 if (area) { 3785 area->width++; 3786 } 3787 drawGlow(cr, area, x - 4, y, width + 5, height, 3788 round, WIDGET_OTHER); 3789 } 3790 3791 if (notebook && opts.highlightTab && active) { 3792 Cairo::vLine(cr, x + width - 3, y + 1, height - 2, selCol1, 0.5); 3793 Cairo::vLine(cr, x + width - 2, y + highlightOffset, 3794 height - 2 * highlightOffset, selCol1); 3795 3796 clipArea.x = x + width - highlightBorder; 3797 clipArea.width = highlightBorder; 3798 drawBorder(cr, style, state, &clipArea, x, y, 3799 width, height, qtcPalette.highlight, ROUNDED_RIGHT, 3800 BORDER_FLAT, WIDGET_OTHER, 0, 3); 3801 } 3802 3803 if (opts.colorSelTab && notebook && active) 3804 colorTab(cr, x, y + mod + sizeAdjust, width - 1, 3805 height - 2 * (mod + sizeAdjust), round, 3806 WIDGET_TAB_BOT, false); 3807 3808 if (notebook && opts.coloredMouseOver && highlight && 3809 opts.tabMouseOver != TAB_MO_GLOW) 3810 drawHighlight(cr, x + (opts.tabMouseOver == TAB_MO_TOP ? 3811 width - 2 : -1), 3812 y + (firstTab ? moOffset : 1), 2, 3813 height - (firstTab || lastTab ? moOffset : 1), 3814 nullptr, false, opts.tabMouseOver != TAB_MO_TOP); 3815 break; 3816 } 3817 case GTK_POS_RIGHT: { 3818 /* tabs are on left !!! */ 3819 auto round = (active || (firstTab && lastTab) || 3820 opts.tabMouseOver == TAB_MO_GLOW || 3821 opts.roundAllTabs ? ROUNDED_LEFT : 3822 firstTab ? ROUNDED_TOPLEFT : lastTab ? 3823 ROUNDED_BOTTOMLEFT : ROUNDED_NONE); 3824 cairo_save(cr); 3825 qtcClipPath(cr, x, y, width + 4, height, WIDGET_TAB_TOP, 3826 RADIUS_EXTERNAL, round); 3827 fillTab(cr, style, widget, area, state, col, x + 1, 3828 y + mod + sizeAdjust, width - 1, 3829 height - 2 * (mod + sizeAdjust), false, WIDGET_TAB_TOP, 3830 notebook != nullptr); 3831 cairo_restore(cr); 3832 drawBorder(cr, style, state, area, x, y + sizeAdjust, 3833 width + 4, height - 2 * sizeAdjust, 3834 glowMo ? qtcPalette.mouseover : qtcPalette.background, 3835 round, borderProfile, WIDGET_TAB_TOP, 0); 3836 if (drawOuterGlow) { 3837 if (area) { 3838 area->x--; 3839 area->width += 2; 3840 } 3841 drawGlow(cr, area, x - 1, y, width + 5, height, 3842 round, WIDGET_OTHER); 3843 } 3844 if (notebook && opts.highlightTab && active) { 3845 Cairo::vLine(cr, x + 2, y + 1, height - 2, selCol1, 0.5); 3846 Cairo::vLine(cr, x + 1, y + highlightOffset, 3847 height - 2 * highlightOffset, selCol1); 3848 3849 clipArea.x = x; 3850 clipArea.width = highlightBorder; 3851 drawBorder(cr, style, state, &clipArea, x, y, 3852 width, height, qtcPalette.highlight, ROUNDED_LEFT, 3853 BORDER_FLAT, WIDGET_OTHER, 0, 3); 3854 } 3855 3856 if (opts.colorSelTab && notebook && active) 3857 colorTab(cr, x + 1, y + mod + sizeAdjust, width - 1, 3858 height - 2 * (mod + sizeAdjust), round, 3859 WIDGET_TAB_TOP, false); 3860 3861 if (notebook && opts.coloredMouseOver && highlight && 3862 opts.tabMouseOver != TAB_MO_GLOW) 3863 drawHighlight(cr, x + (opts.tabMouseOver == TAB_MO_TOP ? 3864 0 : width - 1), 3865 y + (firstTab ? moOffset : 1), 2, 3866 height - (firstTab || lastTab ? moOffset : 1), 3867 nullptr, false, opts.tabMouseOver == TAB_MO_TOP); 3868 break; 3869 } 3870 } 3871 } 3872 3873 void 3874 drawToolbarBorders(cairo_t *cr, GtkStateType state, int x, int y, int width, 3875 int height, bool isActiveWindowMenubar, const char *detail) 3876 { 3877 bool top = false; 3878 bool bottom = false; 3879 bool left = false; 3880 bool right = false; 3881 bool all = oneOf(opts.toolbarBorders, TB_LIGHT_ALL, TB_DARK_ALL); 3882 int border = oneOf(opts.toolbarBorders, TB_DARK, TB_DARK_ALL) ? 3 : 4; 3883 const GdkColor *cols = (isActiveWindowMenubar && 3884 (state != GTK_STATE_INSENSITIVE || 3885 opts.shadeMenubars != SHADE_NONE) ? 3886 menuColors(isActiveWindowMenubar) : 3887 qtcPalette.background); 3888 if (oneOf(detail, "menubar")) { 3889 if (all) { 3890 top = bottom = left = right = true; 3891 } else { 3892 bottom = true; 3893 } 3894 } else if (oneOf(detail, "toolbar")) { 3895 if (all) { 3896 if (width < height) { 3897 left = right = bottom = true; 3898 } else { 3899 top = bottom = right = true; 3900 } 3901 } else { 3902 if (width < height) { 3903 left = right = true; 3904 } else { 3905 top = bottom = true; 3906 } 3907 } 3908 } else if (oneOf(detail,"dockitem_bin", "handlebox_bin")) { 3909 /* CPD: bit risky - what if only 1 item ??? */ 3910 if (all) { 3911 if (width < height) { 3912 left = right = bottom = true; 3913 } else { 3914 top = bottom = right = true; 3915 } 3916 } else { 3917 if (width < height) { 3918 left = right = true; 3919 } else { 3920 top = bottom = true; 3921 } 3922 } 3923 } else { 3924 /* handle */ 3925 if (all) { 3926 if (width < height) { 3927 /* on horiz toolbar */ 3928 top = bottom = left = true; 3929 } else { 3930 left = right = top = true; 3931 } 3932 } else { 3933 if (width < height) { 3934 /* on horiz toolbar */ 3935 top = bottom = true; 3936 } else { 3937 left = right = true; 3938 } 3939 } 3940 } 3941 if (top) { 3942 Cairo::hLine(cr, x, y, width, cols); 3943 } 3944 if (left) { 3945 Cairo::vLine(cr, x, y, height, cols); 3946 } 3947 if (bottom) { 3948 Cairo::hLine(cr, x, y + height - 1, width, &cols[border]); 3949 } 3950 if (right) { 3951 Cairo::vLine(cr, x + width - 1, y, height, &cols[border]); 3952 } 3953 } 3954 3955 void 3956 drawListViewHeader(cairo_t *cr, GtkStateType state, const GdkColor *btnColors, 3957 int bgnd, const QtcRect *area, int x, int y, 3958 int width, int height) 3959 { 3960 drawBevelGradient(cr, area, x, y, width, height, &btnColors[bgnd], 3961 true, state == GTK_STATE_ACTIVE || bgnd == 2 || bgnd == 3, 3962 opts.lvAppearance, WIDGET_LISTVIEW_HEADER); 3963 3964 if (opts.lvAppearance == APPEARANCE_RAISED) { 3965 Cairo::hLine(cr, x, y + height - 2, width, &qtcPalette.background[4]); 3966 } 3967 Cairo::hLine(cr, x, y + height - 1, width, 3968 &qtcPalette.background[QTC_STD_BORDER]); 3969 3970 if (state == GTK_STATE_PRELIGHT && opts.coloredMouseOver) { 3971 drawHighlight(cr, x, y + height - 2, width, 2, area, true, true); 3972 } 3973 3974 #if GTK_CHECK_VERSION(2, 90, 0) /* Gtk3:TODO !!! */ 3975 drawFadedLine(cr, x + width - 2, y + 4, 1, height - 8, 3976 &btnColors[QTC_STD_BORDER], area, nullptr, true, true, false); 3977 drawFadedLine(cr, x + width - 1, y + 4, 1, height - 8, &btnColors[0], 3978 area, nullptr, true, true, false); 3979 #else 3980 if (x > 3 && height > 10) { 3981 drawFadedLine(cr, x, y + 4, 1, height - 8, &btnColors[QTC_STD_BORDER], 3982 area, nullptr, true, true, false); 3983 drawFadedLine(cr, x + 1, y + 4, 1, height - 8, &btnColors[0], 3984 area, nullptr, true, true, false); 3985 } 3986 #endif 3987 } 3988 3989 void 3990 drawDefBtnIndicator(cairo_t *cr, GtkStateType state, const GdkColor *btnColors, 3991 int bgnd, bool sunken, const QtcRect *area, int x, int y, 3992 int width, int height) 3993 { 3994 if (opts.defBtnIndicator == IND_CORNER) { 3995 int offset = sunken ? 5 : 4; 3996 int etchOffset = opts.buttonEffect != EFFECT_NONE ? 1 : 0; 3997 // TODO: used to be switching between focus and highlight 3998 const GdkColor *cols = qtcPalette.focus; 3999 const GdkColor *col = &cols[state == GTK_STATE_ACTIVE ? 0 : 4]; 4000 4001 cairo_new_path(cr); 4002 Cairo::setColor(cr, col); 4003 cairo_move_to(cr, x + offset + etchOffset, y + offset + etchOffset); 4004 cairo_line_to(cr, x + offset + 6 + etchOffset, y + offset + etchOffset); 4005 cairo_line_to(cr, x + offset + etchOffset, y + offset + 6 + etchOffset); 4006 cairo_fill(cr); 4007 } else if (opts.defBtnIndicator == IND_COLORED && COLORED_BORDER_SIZE > 2) { 4008 // offset needed because of etch 4009 int o = (COLORED_BORDER_SIZE + 4010 (opts.buttonEffect != EFFECT_NONE ? 1 : 0)); 4011 drawBevelGradient(cr, area, x + o, y + o, width - 2 * o, 4012 height - 2 * o, &btnColors[bgnd], true, 4013 state == GTK_STATE_ACTIVE, opts.appearance, 4014 WIDGET_STD_BUTTON); 4015 } 4016 } 4017 4018 static GdkPixbuf* 4019 scaleOrRef(GdkPixbuf *src, int width, int height) 4020 { 4021 if (gdk_pixbuf_get_width(src) == width && 4022 gdk_pixbuf_get_height(src) == height) { 4023 return (GdkPixbuf*)g_object_ref(G_OBJECT(src)); 4024 } else { 4025 return gdk_pixbuf_scale_simple(src, width, height, GDK_INTERP_BILINEAR); 4026 } 4027 } 4028 4029 static GdkPixbuf* 4030 setTransparency(const GdkPixbuf *pixbuf, double alpha_percent) 4031 { 4032 QTC_RET_IF_FAIL(pixbuf != nullptr, nullptr); 4033 QTC_RET_IF_FAIL(GDK_IS_PIXBUF(pixbuf), nullptr); 4034 /* Returns a copy of pixbuf with it's non-completely-transparent pixels to 4035 have an alpha level "alpha_percent" of their original value. */ 4036 GdkPixbuf *target = gdk_pixbuf_add_alpha (pixbuf, false, 0, 0, 0); 4037 if (alpha_percent == 1.0) { 4038 return target; 4039 } else { 4040 unsigned width = gdk_pixbuf_get_width(target); 4041 unsigned height = gdk_pixbuf_get_height(target); 4042 unsigned rowstride = gdk_pixbuf_get_rowstride(target); 4043 unsigned char *data = gdk_pixbuf_get_pixels(target); 4044 for (unsigned y = 0;y < height;y++) { 4045 for (unsigned x = 0;x < width;x++) { 4046 data[y * rowstride + x * 4 + 3] *= alpha_percent; 4047 } 4048 } 4049 } 4050 return target; 4051 } 4052 4053 GdkPixbuf* 4054 renderIcon(GtkStyle *style, const GtkIconSource *source, GtkStateType state, 4055 GtkIconSize size, GtkWidget *widget) 4056 { 4057 int width = 1; 4058 int height = 1; 4059 GdkPixbuf *scaled; 4060 GdkPixbuf *stated; 4061 GdkPixbuf *base_pixbuf; 4062 GdkScreen *screen; 4063 GtkSettings *settings; 4064 bool scaleMozilla = (opts.mapKdeIcons && isMozilla() && 4065 size == GTK_ICON_SIZE_DIALOG); 4066 4067 /* Oddly, style can be nullptr in this function, because GtkIconSet can be 4068 * used without a style and if so it uses this function. */ 4069 base_pixbuf = gtk_icon_source_get_pixbuf(source); 4070 4071 QTC_RET_IF_FAIL(base_pixbuf != nullptr, nullptr); 4072 4073 if (widget && gtk_widget_has_screen(widget)) { 4074 screen = gtk_widget_get_screen(widget); 4075 settings = screen ? gtk_settings_get_for_screen(screen) : nullptr; 4076 } 4077 #if GTK_CHECK_VERSION(2, 90, 0) 4078 else if (style->visual) { 4079 screen = gdk_visual_get_screen(style->visual); 4080 settings = screen ? gtk_settings_get_for_screen(screen) : nullptr; 4081 } 4082 #else 4083 else if(style->colormap) { 4084 screen = gdk_colormap_get_screen(style->colormap); 4085 settings = screen ? gtk_settings_get_for_screen(screen) : nullptr; 4086 } 4087 #endif 4088 else { 4089 settings = gtk_settings_get_default(); 4090 GTK_NOTE(MULTIHEAD, g_warning("Using the default screen for " 4091 "gtk_default_render_icon()")); 4092 } 4093 4094 if (scaleMozilla) { 4095 width = height = 48; 4096 } else if (size != (GtkIconSize)-1 && 4097 !gtk_icon_size_lookup_for_settings(settings, size, 4098 &width, &height)) { 4099 g_warning(G_STRLOC ": invalid icon size '%d'", size); 4100 return nullptr; 4101 } 4102 4103 /* If the size was wildcarded, and we're allowed to scale, then scale; 4104 * otherwise, leave it alone. */ 4105 if (scaleMozilla || (size != (GtkIconSize)-1 && 4106 gtk_icon_source_get_size_wildcarded(source))) { 4107 scaled = scaleOrRef(base_pixbuf, width, height); 4108 } else { 4109 scaled = (GdkPixbuf*)g_object_ref(G_OBJECT(base_pixbuf)); 4110 } 4111 4112 /* If the state was wildcarded, then generate a state. */ 4113 if (gtk_icon_source_get_state_wildcarded(source)) { 4114 if (state == GTK_STATE_INSENSITIVE) { 4115 stated = setTransparency(scaled, 0.5); 4116 gdk_pixbuf_saturate_and_pixelate(stated, stated, 0.0, false); 4117 g_object_unref(scaled); 4118 } 4119 #if 0 /* KDE does not highlight icons */ 4120 else if (state == GTK_STATE_PRELIGHT) { 4121 stated = gdk_pixbuf_copy(scaled); 4122 gdk_pixbuf_saturate_and_pixelate(scaled, stated, 1.2, false); 4123 g_object_unref(scaled); 4124 } 4125 #endif 4126 else { 4127 stated = scaled; 4128 } 4129 } else { 4130 stated = scaled; 4131 } 4132 return stated; 4133 } 4134 4135 }