1// Drawing mixins
2
3// generic drawing of more complex things
4
5@function _widget_edge($c:$borders_edge) {
6// outer highlight "used" on most widgets
7  @if $c == none { @return none; }
8  @else { @return 0 1px $c; }
9}
10
11@mixin _shadows($shadow1, $shadow2:none, $shadow3:none, $shadow4:none) {
12//
13// Helper function to stack up to 4 box-shadows;
14//
15  @if $shadow4!=none { box-shadow: $shadow1, $shadow2, $shadow3, $shadow4; }
16  @else if $shadow3!=none { box-shadow: $shadow1, $shadow2, $shadow3; }
17  @else if $shadow2!=none { box-shadow: $shadow1, $shadow2; }
18  @else { box-shadow: $shadow1; }
19}
20
21// entries
22
23@function entry_focus_border($fc:$selected_bg_color) {
24  @return $fc;
25}
26
27@function entry_focus_shadow($fc:$selected_bg_color) {
28  @return inset 0 0 0 1px $fc;
29}
30
31@function entry_gradient($c) {
32  @if $variant=='light' { @return linear-gradient(to bottom, mix($borders_color, $c, 45%),
33                                                             mix($borders_color, $c, 3%) 2px,
34                                                             $c 90%); }
35  @else { @return linear-gradient(to bottom, mix($borders_color, $c, 95%),
36                                             mix($borders_color, $c, 40%) 3px,
37                                             $c 90%); }
38}
39
40@mixin entry($t, $fc:$selected_bg_color, $edge: none) {
41//
42// Entries drawing function
43//
44// $t: entry type
45// $fc: focus color
46// $edge: set to none to not draw the bottom edge or specify a color to not
47//        use the default one
48//
49// possible $t values:
50// normal, focus, insensitive, backdrop, backdrop-insensitive, osd, osd-focus, osd-backdrop;
51//
52
53  $_blank_edge: if($edge == none, none, 0 1px transparentize($edge, 1));
54  $_entry_edge: if($edge == none, none, _widget_edge($edge));
55
56  @if $t==normal {
57    color: $text_color;
58    border-color: $borders_color;
59    background-color: $base_color;
60    @include _shadows(entry_focus_shadow(transparentize($fc, 1)), $_entry_edge);
61    // for the transition to work the number of shadows in different states needs to match, hence the transparent shadow here.
62  }
63  @if $t==focus {
64    border-color: entry_focus_border($fc);
65  }
66  @if $t==insensitive {
67    color: $insensitive_fg_color;
68    border-color: $borders_color;
69    background-color: $insensitive_bg_color;
70    box-shadow: $_entry_edge;
71  }
72  @if $t==backdrop {
73    color: $backdrop_text_color;
74    border-color: $backdrop_borders_color;
75    background-color: $backdrop_base_color;
76    box-shadow: $_blank_edge;
77  }
78  @if $t==backdrop-insensitive {
79    color: $backdrop_insensitive_color;
80    border-color: $backdrop_borders_color;
81    background-color: $insensitive_bg_color;
82    box-shadow: $_blank_edge;
83  }
84  @if $t==osd {
85    color: $osd_text_color;
86    border-color: $osd_borders_color;
87    background-color: transparentize(opacify($osd_borders_color, 1), 0.5);
88    background-clip: padding-box;
89    box-shadow: none;
90    text-shadow: 0 1px black;
91    -gtk-icon-shadow: 0 1px black;
92  }
93  @if $t==osd-focus {
94    color: $osd_text_color;
95    border-color: $selected_bg_color;
96    background-color: transparentize(opacify($osd_borders_color, 1), 0.5);
97    background-clip: padding-box;
98    box-shadow: entry_focus_shadow($fc);
99    text-shadow: 0 1px black;
100    -gtk-icon-shadow: 0 1px black;
101  }
102  @if $t==osd-insensitive {
103    color: $osd_insensitive_fg_color;
104    border-color: $osd_borders_color;
105    background-color: $osd_insensitive_bg_color;
106    background-clip: padding-box;
107    box-shadow: none;
108    text-shadow: none;
109    -gtk-icon-shadow: none;
110  }
111  @if $t==osd-backdrop {
112    color: $osd_text_color;
113    border-color: $osd_borders_color;
114    background-color: transparentize(opacify($osd_borders_color, 1), 0.5);
115    background-clip: padding-box;
116    box-shadow: none;
117    text-shadow: none;
118    -gtk-icon-shadow: none;
119  }
120}
121
122// buttons
123
124@function _border_color ($c) { @return darken($c, 25%); } // colored buttons want
125                                                         // the border form the
126                                                         // base color
127
128@function _text_shadow_color ($tc: $fg_color, $bg: $bg_color) {
129//
130// calculate the color of text shadows
131//
132// $tc is the text color
133// $bg is the background color
134//
135  $_lbg: lightness($bg)/100%;
136  @if lightness($tc)<50% { @return transparentize(white, 1-$_lbg/($_lbg*1.3)); }
137  @else { @return transparentize(black, $_lbg*0.8); }
138}
139
140@function _button_hilight_color($c) {
141//
142// calculate the right top hilight color for buttons
143//
144// $c: base color;
145//
146  @if lightness($c)>95% { @return white; }
147  @else if lightness($c)>90% { @return transparentize(white, 0.2); }
148  @else if lightness($c)>80% { @return transparentize(white, 0.4); }
149  @else if lightness($c)>50% { @return transparentize(white, 0.6); }
150  @else if lightness($c)>40% { @return transparentize(white, 0.8); }
151  @else { @return transparentize(white, 0.95); }
152}
153
154@mixin _button_text_shadow ($tc:$fg_color, $bg:$bg_color) {
155//
156// helper function for the text emboss effect
157//
158// $tc is the optional text color, not the shadow color
159//
160// TODO: this functions needs a way to deal with special cases
161//
162
163  $_shadow: _text_shadow_color($tc, $bg);
164
165  @if lightness($tc)<50% {
166    text-shadow: 0 1px $_shadow;
167    -gtk-icon-shadow: 0 1px $_shadow;
168  }
169  @else {
170    text-shadow: 0 -1px $_shadow;
171    -gtk-icon-shadow: 0 -1px $_shadow;
172  }
173}
174
175@mixin button($t, $c:$bg_color, $tc:$fg_color, $edge: none) {
176//
177// Button drawing function
178//
179// $t:    button type,
180// $c:    base button color for colored* types
181// $tc:   optional text color for colored* types
182// $edge: set to none to not draw the bottom edge or specify a color to not
183//        use the default one
184//
185// possible $t values:
186// normal, hover, active, insensitive, insensitive-active,
187// backdrop, backdrop-active, backdrop-insensitive, backdrop-insensitive-active,
188// osd, osd-hover, osd-active, osd-insensitive, osd-backdrop, undecorated
189//
190
191  $_hilight_color: _button_hilight_color($c);
192  $_button_edge: if($edge == none, none, _widget_edge($edge));
193  $_blank_edge: if($edge == none, none, _widget_edge(transparentize($edge,1)));
194
195  @if $t==normal {
196  //
197  // normal button
198  //
199    color: $tc;
200    outline-color: transparentize($tc, 0.7);
201    border-top-color: shade($bg_color, 0.8);
202    border-right-color: shade($bg_color, 0.72);
203    border-left-color: shade($bg_color, 0.72);
204    border-bottom-color: shade($bg_color, 0.7);
205    @if $variant == 'light' { background-image: linear-gradient(to bottom, shade(shade($c, 1.02), 1.05), shade(shade($c, 1.02), 0.97)); }
206    @else { background-image: linear-gradient(to bottom, darken($c, 2%), darken($c, 4%) 60%, darken($c, 6%)); }
207    @include _shadows(inset 0 1px $_hilight_color, $_button_edge);
208  }
209
210  @else if $t==hover {
211  //
212  // hovered button
213  //
214    color: $tc;
215    outline-color: transparentize($tc, 0.7);
216    border-color: if($c!=$bg_color, _border_color($c), $borders_color);
217    @if $variant == 'light' {
218      background-image: linear-gradient(to bottom, shade($c, 1.15), shade($c, 1.07));
219      @include _shadows(inset 0 1px _button_hilight_color(lighten($c, 6%)), $_button_edge);
220    }
221    @else {
222      background-image: linear-gradient(to bottom, lighten($c, 1%), darken($c, 2%) 60%, darken($c, 4%));
223      @include _shadows(inset 0 1px _button_hilight_color(darken($c, 2%)), $_button_edge);
224    }
225  }
226
227  @if $t==normal-alt {
228  //
229  // normal button alternative look
230  //
231    color: $tc;
232    outline-color: transparentize($tc, 0.7);
233    border-color: if($c!=$bg_color, _border_color($c), $borders_color);
234    @if $variant == 'light' {
235      background-image: linear-gradient(to bottom, lighten($c, 5%) 20%, $c 90%);
236      @include _shadows(inset 0 1px _button_hilight_color(lighten($c, 6%)),
237                        inset 0 -2px lighten($c, 2%),
238                        inset 0 -1px darken($c, 12%),
239                        $_button_edge);
240    }
241    @else {
242      background-image: linear-gradient(to bottom, darken($c, 3%) 20%, darken($c, 6%) 90%);
243      @include _shadows(inset 0 1px $_hilight_color,
244                        inset 0 -2px darken($c, 4%),
245                        inset 0 -1px darken($c, 9%),
246                        $_button_edge);
247    }
248  }
249
250  @else if $t==hover-alt {
251  //
252  // hovered button alternative look
253  //
254    color: $tc;
255    outline-color: transparentize($tc, 0.7);
256    border-color: if($c!=$bg_color, _border_color($c), $borders_color);
257    @if $variant == 'light' {
258      background-image: linear-gradient(to bottom, lighten($c, 9%) 10%, lighten($c, 4%) 90%);
259      box-shadow: inset 0 1px _button_hilight_color(lighten($c, 6%)),
260                  inset 0 -2px lighten($c, 5%),
261                  inset 0 -1px darken($c, 10%),
262                  $_button_edge;
263    }
264    @else {
265      background-image: linear-gradient(to bottom, $c 20%, darken($c, 4%) 90%);
266      @include _shadows(inset 0 1px $_hilight_color,
267                        inset 0 -2px darken($c, 3%),
268                        inset 0 -1px darken($c, 6%),
269                        $_button_edge);
270    }
271  }
272
273
274  @else if $t==active {
275  //
276  // pushed button
277  //
278    color: $tc;
279    outline-color: transparentize($tc, 0.7);
280    border-color: if($c!=$bg_color, _border_color($c), $borders_color);
281    @if $variant == 'light' { background-image: linear-gradient(to bottom, shade(shade($c, 0.85), 1.05), shade(shade($c, 0.85), 0.97)); }
282    @else { background-image: linear-gradient(to bottom, darken($c, 9%), darken($c, 5%)); }
283    @include _shadows(inset 0 2px 1px -2px transparentize(black,0.4),
284                      $_button_edge);
285  }
286  @else if $t==insensitive {
287  //
288  // insensitive button
289  //
290    $_bg: if($c!=$bg_color, mix($c, $base_color, 85%), $insensitive_bg_color);
291
292    label, & { color: if($tc!=$fg_color, mix($tc, $_bg, 50%), $insensitive_fg_color); }
293
294    border-color: if($c!=$bg_color, _border_color($c),
295                                    $insensitive_borders_color);
296    background-color: $_bg;
297    text-shadow: none;
298    -gtk-icon-shadow: none;
299    // white with 0 alpha to avoid an ugly transition, since no color means
300    // black with 0 alpha
301    @include _shadows(inset 0 1px transparentize(white, 1), $_button_edge);
302  }
303  @else if $t==insensitive-active {
304  //
305  // insensitive pushed button
306  //
307    $_bg: if($c!=$bg_color, darken(mix($c,$base_color, 85%), 5%),
308                            $insensitive_bg_color);
309    $_bc: if($c!=$bg_color, _border_color($c), $insensitive_borders_color);
310
311    label, & { color: if($c!=$bg_color, mix($tc, $_bg, 60%), $insensitive_fg_color); }
312
313    border-color: $_bc;
314    background-image: linear-gradient(to bottom, mix($_bc, $_bg, 10%), $_bg);
315    // white with 0 alpha to avoid an ugly transition, since no color means
316    // black with 0 alpha
317    @include _shadows(inset 0 1px transparentize(white, 1), $_button_edge);
318  }
319
320  @else if $t==backdrop {
321  //
322  // backdrop button
323  //
324    $_bg: if($c!=$bg_color,$c,$backdrop_bg_color);
325    $_bc: if($variant=='light',$c,_border_color($c));
326
327    label, & { color: if($tc!=$fg_color,mix($tc, $_bg, 80%), $backdrop_fg_color); }
328
329    border-color: if($c!=$bg_color, $_bc, $backdrop_borders_color);
330    background-color: $_bg;
331    text-shadow: none;
332    -gtk-icon-shadow: none;
333    @include _shadows(inset 0 1px transparentize(white, 1),
334                      $_blank_edge);
335  }
336
337  @else if $t==backdrop-active {
338  //
339  // backdrop pushed button FIXME no colors here!
340  //
341    $_bg: if($c!=$bg_color, darken($c, 10%), $backdrop_dark_fill);
342    $_bc: if($variant=='light',$_bg,_border_color($c));
343
344    label, & { color: if($tc!=$fg_color, mix($tc, $_bg, 80%), $backdrop_fg_color); }
345
346    border-color: if($c!=$bg_color, $_bc, $backdrop_borders_color);
347    background-color: $_bg;
348    @include _shadows(inset 0 1px transparentize(white, 1),
349                      $_blank_edge);
350  }
351
352  @else if $t==backdrop-insensitive {
353  //
354  // backdrop insensitive button
355  //
356
357    $_bg: if($c!=$bg_color, mix($c, $base_color, 85%), $insensitive_bg_color);
358    $_bc: if($variant=='light', $_bg,_border_color($c));
359
360    label, & { color: if($c!=$bg_color, mix($tc, $_bg, 35%), $backdrop_insensitive_color); }
361
362    border-color: if($c!=$bg_color, $_bc, $backdrop_borders_color);
363    background-color: $_bg;
364    text-shadow: none;
365    -gtk-icon-shadow: none;
366    // white with 0 alpha to avoid an ugly transition, since no color means
367    // black with 0 alpha
368    @include _shadows(inset 0 1px transparentize(white, 1),
369                      $_blank_edge);
370  }
371
372  @else if $t==backdrop-insensitive-active {
373  //
374  // backdrop insensitive pushed button
375  //
376
377    $_bg: if($c!=$bg_color, darken(mix($c, $base_color, 85%), 5%),
378                            darken($insensitive_bg_color, 5%));
379    $_bc: if($variant=='light', $_bg,_border_color($c));
380
381    label { color: if($c!=$bg_color, mix($tc, $_bg, 35%), $backdrop_insensitive_color); }
382
383    border-color: if($c!=$bg_color, $_bc, $backdrop_borders_color);
384    background-color: $_bg;
385    @include _shadows(inset 0 1px transparentize(white, 1),
386                      $_blank_edge);
387  }
388
389  @else if $t==osd {
390  //
391  // normal osd button
392  //
393    $_bg: if($c!=$bg_color, transparentize($c, 0.5),
394                            $osd_bg_color);
395
396    color: $osd_fg_color;
397    border-color: $osd_borders_color;
398    background-color: $_bg;
399    background-clip: padding-box;
400    box-shadow: inset 0 1px transparentize(white, 0.9);
401    text-shadow: 0 1px black;
402    -gtk-icon-shadow: 0 1px black;
403    outline-color: transparentize($osd_fg_color, 0.7);
404  }
405  @else if $t==osd-hover {
406  //
407  // active osd button
408  //
409    $_bg: if($c!=$bg_color, transparentize($c, 0.3),
410                            lighten($osd_bg_color, 12%));
411
412    color: white;
413    border-color: $osd_borders_color;
414    background-color: $_bg;
415    background-clip: padding-box;
416    box-shadow: inset 0 1px transparentize(white, 0.9);
417    text-shadow: 0 1px black;
418    -gtk-icon-shadow: 0 1px black;
419    outline-color: transparentize($osd_fg_color, 0.7);
420  }
421  @else if $t==osd-active {
422  //
423  // active osd button
424  //
425    $_bg: if($c!=$bg_color, $c, $osd_borders_color);
426
427    color: white;
428    border-color: $osd_borders_color;
429    background-color: $_bg;
430    background-clip: padding-box;
431    box-shadow: none;
432    text-shadow: none;
433    -gtk-icon-shadow: none;
434    outline-color: transparentize($osd_fg_color, 0.7);
435  }
436  @else if $t==osd-insensitive {
437  //
438  // insensitive osd button
439  //
440    color: $osd_insensitive_fg_color;
441    border-color: $osd_borders_color;
442    background-color: $osd_insensitive_bg_color;
443    background-clip: padding-box;
444    box-shadow: none;
445    text-shadow: none;
446    -gtk-icon-shadow: none;
447  }
448  @else if $t==osd-backdrop {
449  //
450  // backdrop osd button
451  //
452    $_bg: if($c!=$bg_color, transparentize($c, 0.5),
453                            $osd_bg_color);
454
455    color: $osd_fg_color;
456    border-color: $osd_borders_color;
457    background-color: $_bg;
458    background-clip: padding-box;
459    box-shadow: none;
460    text-shadow: none;
461    -gtk-icon-shadow: none;
462  }
463  @else if $t==undecorated {
464  //
465  // reset
466  //
467    border-color: transparent;
468    background-color: transparent;
469    background-image: none;
470
471    @include _shadows(inset 0 1px transparentize(white, 1),
472                      $_blank_edge);
473
474    text-shadow: none;
475    -gtk-icon-shadow: none;
476  }
477}
478
479@mixin trough($flat:false, $c:$bg_color, $tc:$fg_color, $noedge:true) {
480  color: mix($tc, $bg_color, 80%);
481  @if $flat { background-color: $c; }
482  @else {
483    background-image: linear-gradient(to bottom,
484                                      mix(black,$c,15%) 5%,
485                                      mix(black,$c,10%) 20%,
486                                      mix(black,$c,10%) 90%,
487                                      $c);
488  }
489
490  border-color: if($c!=$bg_color, _border_color($c), $border_color);
491
492  @if not($noedge) {
493    @if lightness($c) > 60% {
494      box-shadow: inset 0 -1px $borders_edge,
495                  0 1px $borders_edge;
496    }
497    @else {
498      box-shadow: inset 0 -1px transparentize($borders_edge, 0.5),
499                  0 1px transparentize($borders_edge, 0.5);
500    }
501  }
502  @else { box-shadow: none; }
503}
504
505@mixin headerbar_fill($c:$headerbar_color, $hc:$top_hilight, $ov: none) {
506//
507// headerbar fill
508//
509// $c:  base color
510// $hc: top highlight color
511// $ov: a background layer for background shorthand (hence no commas!)
512//
513  $gradient: linear-gradient(to bottom, $c, shade($c, 0.88));
514
515  @if $variant == 'dark' { $gradient: linear-gradient(to top, darken($c, 3%), darken($c, 1%) 2px, $c 3px); }
516
517  @if $ov != none { background: $c $ov, $gradient; }
518  @else { background: $c $gradient; }
519
520  box-shadow: inset 0 1px $hc; // top highlight
521}
522
523@mixin overshoot($p, $t:normal, $c:$fg_color) {
524//
525// overshoot
526//
527// $p: position
528// $t: type
529// $c: base color
530//
531// possible $p values:
532// top, bottom, right, left
533//
534// possible $t values:
535// normal, backdrop
536//
537
538  $_small_gradient_length: 5%;
539  $_big_gradient_length: 100%;
540
541  $_position: center top;
542  $_small_gradient_size: 100% $_small_gradient_length;
543  $_big_gradient_size: 100% $_big_gradient_length;
544
545  @if $p==bottom {
546    $_position: center bottom;
547    $_linear_gradient_direction: to top;
548  }
549
550  @else if $p==right {
551    $_position: right center;
552    $_small_gradient_size: $_small_gradient_length 100%;
553    $_big_gradient_size: $_big_gradient_length 100%;
554  }
555
556  @else if $p==left {
557    $_position: left center;
558    $_small_gradient_size: $_small_gradient_length 100%;
559    $_big_gradient_size: $_big_gradient_length 100%;
560  }
561
562  $_small_gradient_color: $c;
563  $_big_gradient_color: $c;
564
565  @if $c==$fg_color {
566    $_small_gradient_color: darken($borders_color, 10%);
567    $_big_gradient_color: $fg_color;
568
569    @if $t==backdrop { $_small_gradient_color: $backdrop_borders_color; }
570  }
571
572  $_small_gradient: -gtk-gradient(radial,
573                                  $_position, 0,
574                                  $_position, 0.5,
575                                  to($_small_gradient_color),
576                                  to(transparentize($_small_gradient_color, 1)));
577
578  $_big_gradient: -gtk-gradient(radial,
579                                $_position, 0,
580                                $_position, 0.6,
581                                from(transparentize($_big_gradient_color, 0.93)),
582                                to(transparentize($_big_gradient_color, 1)));
583
584  @if $t==normal {
585    background-image: $_small_gradient, $_big_gradient;
586    background-size: $_small_gradient_size, $_big_gradient_size;
587  }
588
589  @else if $t==backdrop {
590    background-image: $_small_gradient;
591    background-size: $_small_gradient_size;
592  }
593
594  background-repeat: no-repeat;
595  background-position: $_position;
596
597  background-color: transparent; // reset some properties to be sure to not inherit them somehow
598  border: none;                  //
599  box-shadow: none;              //
600}
601
602@mixin undershoot($p) {
603//
604// undershoot
605//
606// $p: position
607//
608// possible $p values:
609// top, bottom, right, left
610//
611
612  $_undershoot_color_dark: transparentize(black, 0.8);
613  $_undershoot_color_light: transparentize(white, 0.8);
614
615  $_gradient_dir: left;
616  $_dash_bg_size: 10px 1px;
617  $_gradient_repeat: repeat-x;
618  $_bg_pos: center $p;
619
620  background-color: transparent; // shouldn't be needed, but better to be sure;
621
622  @if ($p == left) or ($p == right) {
623    $_gradient_dir: top;
624    $_dash_bg_size: 1px 10px;
625    $_gradient_repeat: repeat-y;
626    $_bg_pos: $p center;
627  }
628
629  background-image: linear-gradient(to $_gradient_dir, // this is the dashed line
630                                    $_undershoot_color_light 50%,
631                                    $_undershoot_color_dark 50%);
632
633  padding-#{$p}: 1px;
634  background-size: $_dash_bg_size;
635  background-repeat: $_gradient_repeat;
636  background-origin: content-box;
637  background-position: $_bg_pos;
638  border: none;
639  box-shadow: none;
640}
641