From ba4c351ce37a73946f349a2cfc6b4285fd4e9521 Mon Sep 17 00:00:00 2001 From: Himadri Sekhar Basu <41947504+hsbasu@users.noreply.github.com> Date: Wed, 10 Apr 2024 00:42:16 +0530 Subject: [PATCH] Update common build scripts (#77) - Rebase common build scripts from yaru - Update meson build scripts for gtk and metacity - Update version in meson build script - Update test script --- common/accent-colors.scss.in | 16 +++- common/colorize-dummy-svg.py | 12 +++ common/sass-utils.scss | 139 ++++++++++++++++++++++++++++---- common/sucharu-colors-defs.scss | 18 +++-- common/test-sass-utils.scss | 47 ++++++++++- gtk/src/meson.build | 8 +- meson.build | 2 +- metacity/src/meson.build | 4 +- test-sucharu | 4 +- 9 files changed, 219 insertions(+), 31 deletions(-) diff --git a/common/accent-colors.scss.in b/common/accent-colors.scss.in index 51fa62f6..8a94f4fd 100644 --- a/common/accent-colors.scss.in +++ b/common/accent-colors.scss.in @@ -1,3 +1,5 @@ +@import 'sass-utils'; + @function get_accent_color($accent_color, $is_dark: false) { $color: null; @if $accent_color == 'default' { @@ -30,9 +32,19 @@ } $sucharu_is_dark_variant: @sucharu_dark_variant@; +$jet: #181818; +$sucharu_bg_color: if($sucharu_is_dark_variant, #FAFAFA, lighten($jet, 8%)); $sucharu_accent_bg_color: get_accent_color('@sucharu_accent_color@', $sucharu_is_dark_variant); -$accent_bg_color: $sucharu_accent_bg_color; -$accent_color: $sucharu_accent_bg_color; + +$contrast_target: if($sucharu_is_dark_variant, 4.5, 4.8); +$sucharu_accent_color: optimize-contrast($sucharu_bg_color, + $sucharu_accent_bg_color, $target: $contrast_target); + @debug("Accent color is " + $sucharu_accent_bg_color); +@debug("Contrast optimized accent is " + $sucharu_accent_color); + +$accent_bg_color: $sucharu_accent_bg_color; +$accent_fg_color: white; +$accent_color: $sucharu_accent_color; @import '@sucharu_theme_entry_point@' diff --git a/common/colorize-dummy-svg.py b/common/colorize-dummy-svg.py index 7a8a8793..01a4ab0c 100755 --- a/common/colorize-dummy-svg.py +++ b/common/colorize-dummy-svg.py @@ -24,17 +24,29 @@ # Keep this in sync with sucharu-colors-defs.scss, or the input CSS in use. DUMMY_COLORS = { + 'accent-color': '#00ff03', + 'accent-color-hc': '#00ff04', 'accent-bg-color': '#00ff01', + 'accent-bg-color-hc': '#00ff05', 'accent-active-color': '#00ff02', + 'accent-active-color-hc': '#00ff06', 'accent-border-color': '#ff0001', + 'accent-border-color-hc': '#ff0002', 'accent-focused-color': '#0101ff', + 'accent-focused-color-hc': '#0101f1', 'bg-color': '#ffff00', 'border-color': '#ff00ff', + 'border-color-hc': '#ff00f1', 'disabled-bg-color': '#ffff02', + 'disabled-bg-color-hc': '#ffff04', 'switch-bg-color': '#ffff01', + 'switch-bg-color-hc': '#ffff05', 'check-bg-color': '#ffff03', + 'check-bg-color-hc': '#ffff06', } +assert len(set(DUMMY_COLORS.values())) == len(DUMMY_COLORS.values()) + def read_colors_replacements(css_file): colors_replacements = {} diff --git a/common/sass-utils.scss b/common/sass-utils.scss index dd96b83c..ffc263b8 100644 --- a/common/sass-utils.scss +++ b/common/sass-utils.scss @@ -63,41 +63,150 @@ } @function list-length($list) { + @return length($list); +} + +@function list-nth($list, $nth) { + $length: length($list); + @if ($length == 0 or abs($nth) > $length) { + @return null; + } + + @if ($nth >= 0) { + $nth: $nth + 1; + } + + @return nth($list, $nth); +} + +@function list-index($list, $item) { $i: 0; @each $e in $list { + @if ($e == $item) { + @return $i; + } + $i: $i + 1; } - @return $i; + @return null; } -@function list-nth($list, $nth) { - $i: 0; +@function pow($base, $exponent, $root: 1) { + @if ($exponent == 0) { + @return 1; + } - @if $nth < 0 { - $nth: list-length($list) + $nth; + @if ($base == 0) { + @return 0; } - @each $e in $list { - @if ($i == $nth) { - @return $e; + @if ($root != 1) { + @if ($exponent == $root) { + @return $base; } + $base: nth-root($base, $root); + } + @if $exponent < 0 { + $base: 1 / $base; + $exponent: -$exponent; + } @else if ($exponent % 2 == 0) { + $half-pow: pow($base, $exponent / 2); + @return $half-pow * $half-pow; + } + + $i: 1; + $val: $base; + @while ($i < $exponent) { + $val: $val * $base; $i: $i + 1; } - @return null; + @return $val; } -@function list-index($list, $item) { - $i: 0; - @each $e in $list { - @if ($e == $item) { - @return $i; +@function nth-root($value, $n, $max_iterations: 100) { + @if ($n <= 0) { + @error "Not supported" + } + + @if ($n == 1 or $value == 0) { + @return $value; + } + + $i: 1; + $pre-val: 1; + @while ($i < $max_iterations) { + $val: (1.0 / $n) * ((($n - 1) * $pre-val) + $value / pow($pre-val, $n - 1)); + + @if ($pre-val == $val) { + @return $val; } + $pre-val: $val; $i: $i + 1; } - @return null; + @error ("Failed to compute " + $n + "th root of " + $value + " in " + + $max_iterations + " iterations"); +} + +@function truncate($value, $decimals: 10) { + @if ($decimals < 0) { + @error "Not supported" + } + + $multiplier: pow(10, $decimals); + @return floor($value * $multiplier) / $multiplier; +} + +// Credits to https://css-tricks.com/snippets/sass/luminance-color-function/ +@function luminance($color) { + $colors: ( + 'red': red($color), + 'green': green($color), + 'blue': blue($color) + ); + + @each $name, $value in $colors { + $adjusted: 0; + $value: $value / 255; + + @if $value < 0.03928 { + $value: $value / 12.92; + } @else { + $value: ($value + .055) / 1.055; + $value: pow($value, 12, 5); + } + + $colors: map-merge($colors, ($name: $value)); + } + + @return ((map-get($colors, 'red') * .2126) + + (map-get($colors, 'green') * .7152) + + (map-get($colors, 'blue') * .0722)); +} + +@function color-contrast($color1, $color2) { + $c1-luminance: luminance($color1); + $c2-luminance: luminance($color2); + + $lighter-luminance: max($c1-luminance, $c2-luminance); + $darker-luminance: min($c1-luminance, $c2-luminance); + + @return ($lighter-luminance + 0.05) / ($darker-luminance + 0.05); +} + +@function optimize-contrast($bg, $fg, $large-text: false, $target: 4.5) { + @if ($large-text and $target == 4.5) { + $target: 3; + } + + $dark-bg: luminance($fg) > luminance($bg); + @while (color-contrast($bg, $fg) < $target) { + $fg: if($dark-bg, lighten($fg, 0.1), darken($fg, 0.1)); + } + + @return $fg; } diff --git a/common/sucharu-colors-defs.scss b/common/sucharu-colors-defs.scss index 03bfbb77..56e6dcb1 100644 --- a/common/sucharu-colors-defs.scss +++ b/common/sucharu-colors-defs.scss @@ -2,22 +2,24 @@ // assets (dummy) colors via colorize-dummy-svg.py $variant: if($sucharu_is_dark_variant, 'dark', 'light'); +$hc_contrast_target: 5.5; @import 'colors'; $sucharu_colors: ( bg-color: $bg_color, + accent-color: $sucharu_accent_color, accent-bg-color: $sucharu_accent_bg_color, - accent-active-color: if($variant == 'light', darken($accent_bg_color, 15%), darken($accent_bg_color, 20%)), - accent-focused-color: if($variant == 'light', lighten($accent_bg_color, 10%), lighten($accent_bg_color, 7%)), + accent-active-color: if($variant == 'dark', darken($accent_bg_color, 20%), darken($accent_bg_color, 15%)), + accent-focused-color: if($variant == 'dark', darken($accent_bg_color, 7%), darken($accent_bg_color, 3%)), border-color: $borders_color, disabled-bg-color: mix($bg_color, $fg_color, 80%), - switch-bg-color: if($variant == 'light', lighten($ash, 20%), lighten($inkstone, 5%)), - check-bg-color: if($variant == 'light', $porcelain, lighten($bg_color, 2%)), + switch-bg-color: if($variant == 'dark', lighten($inkstone, 10%), lighten($ash, 20%)), + check-bg-color: if($variant == 'dark', lighten($bg_color, 2%), $porcelain), ); $sucharu_colors: map-merge($sucharu_colors, ( - accent-border-color: lighten(map-get($sucharu_colors, accent-active-color), 35%), + accent-border-color: lighten(map-get($sucharu_colors, accent-active-color), 17%), )); @function opaque-color($color, $background: $bg_color) { @@ -39,5 +41,11 @@ $sucharu_colors: map-merge($sucharu_colors, ( @if $opaque != $color { -sucharu-#{$name}-opaque: $opaque; } + + @if $name != "bg-color" and not map-has-key($sucharu_colors, $name + "-hc") and + not str-ends-with($name, "-hc") { + -sucharu-#{$name}-hc: optimize-contrast($bg_color, + $color, $target: $hc_contrast_target); + } } }; diff --git a/common/test-sass-utils.scss b/common/test-sass-utils.scss index 3d75fec3..1ead5465 100644 --- a/common/test-sass-utils.scss +++ b/common/test-sass-utils.scss @@ -18,7 +18,12 @@ @import 'sass-utils'; @function assert($result, $expected: true) { - @if $result != $expected { + @if (type-of($result) == 'color' and type-of($expected) == 'color') { + $result: #{$result}; + $expected: #{$expected}; + } + + @if ($result != $expected or type-of($result) != type-of($expected)) { $result: if($result == null, 'null', $result); $expected: if($expected == null, 'null', $expected); @error "Assertion failed, expected '" + $expected + "', got '" + $result + "'"; @@ -96,3 +101,43 @@ @debug test('list-index, Three, valid', list-index([1, '2', false], 1), 0); @debug test('list-index, Three, valid', list-index([1, '2', false], '2'), 1); @debug test('list-index, Three, valid', list-index([1, '2', false], false), 2); + +@debug test('nth-root 1-root of 0', nth-root(0, 1), 0); +@debug test('nth-root 0-root of 0', nth-root(0, 20), 0); +@debug test('nth-root 2-root of 4', nth-root(4, 2), 2); +@debug test('nth-root 4-root of 256', nth-root(256, 4), 4); +@debug test('nth-root 5-root of 4096', nth-root(4096.0, 5), 5.278031643091578); + +@debug test('pow 0^0', pow(0, 0), 1); +@debug test('pow 1^0', pow(1, 0), 1); +@debug test('pow 10^0', pow(10, 0), 1); + +@debug test('pow 0^10', pow(0, 10), 0); +@debug test('pow 1^20', pow(1, 20), 1); +@debug test('pow 2^8', pow(2, 8), 256); +@debug test('pow 10^3', pow(10, 3), 1000); + +@debug test('pow 2^-2', pow(2, -2), 1/4); +@debug test('pow 3^-3', pow(3, -3), 1/27); + +@debug test('pow 2^(2/2)', pow(2, 2, 2), 2); +@debug test('pow 2^(4/2)', pow(2, 4, 2), 4); +@debug test('pow 2^(12/5)', pow(2, 12, 5), 5.278031643091582); + +@debug test('truncate 0.1234567890123456789', truncate(0.123456789123456789), 0.1234567891); +@debug test('truncate 5 0.12345678901234', truncate(0.12345678901234, 5), 0.12345); +@debug test('truncate 5 0.12345678901234', truncate(0.12345678901234, 1), 0.1); +@debug test('truncate 5 5.12345678901234', truncate(5.12345678901234, 0), 5); + +@debug test('luminance white', luminance(white), 1); +@debug test('luminance black', luminance(black), 0); +@debug test('luminance red', luminance(#f00), 0.2126); +@debug test('luminance green', luminance(#0f0), 0.7152); +@debug test('luminance blue', luminance(#00f), 0.0722); +@debug test('luminance Ubuntu orange', truncate(luminance(#dd4814), 6), 0.200573); + +@debug test('color contrast black/white', color-contrast(white, black), 21); +@debug test('color contrast blue/blue', color-contrast(blue, blue), 1); + +@debug test('optimize-contrast black/blue', optimize-contrast(black, blue), #5e5eff); +@debug test('optimize-contrast white/blue', optimize-contrast(white, lightgray), #767676); diff --git a/gtk/src/meson.build b/gtk/src/meson.build index e31a2997..ddf355e2 100644 --- a/gtk/src/meson.build +++ b/gtk/src/meson.build @@ -9,11 +9,12 @@ gtk_versions = [ ] gtk_sucharu_colors_defs = {} - +sass_global_paths = ['-I', meson.project_source_root() / 'common'] message('\n\nAll flavours: ') message(flavours) foreach flavour: flavours + message('Configuring flavour ' + flavour) suffix = flavour == 'default' ? '' : '-@0@'.format(flavour) theme_name = meson.project_name() + suffix is_dark = flavour == 'dark' or flavour.endswith('-dark') @@ -46,6 +47,7 @@ foreach flavour: flavours ) accent_color_code = run_command(sassc, + sass_global_paths, accent_info_css, check: true).stderr().split(' Accent color is ')[1].strip() assert(accent_color_code.startswith('#'), 'No accent color code found') endif @@ -138,7 +140,7 @@ foreach flavour: flavours # Look for scss files in the variant dir first, otherwise fallback to # base, default or upstream paths, so using reversed order - scss_paths = [] + scss_paths = sass_global_paths gtk_scss_dependencies = [] foreach src: sources_priority scss_paths += ['-I', meson.current_source_dir() / src ] @@ -208,7 +210,7 @@ foreach flavour: flavours ) endforeach install_data(gtk_css, install_dir: install_path) - + # build and install assets foreach src: sources_priority assets_rel_dir = src / 'assets' diff --git a/meson.build b/meson.build index db4517b4..aaebf4a4 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('Sucharu', - version: '2.0.8', + version: '2.0.9', meson_version: '>= 0.60', license : ['GPL3', 'CC BY-SA 4.0'], default_options: ['prefix=/usr']) diff --git a/metacity/src/meson.build b/metacity/src/meson.build index 4d16dd0f..59b55b1d 100644 --- a/metacity/src/meson.build +++ b/metacity/src/meson.build @@ -30,8 +30,8 @@ foreach flavour: flavours # install metacity assets metacity_asset_dir = join_paths(flavour, 'metacity-1') metacity_svg_data = run_command( - 'find', metacity_asset_dir, '-name', '*.svg' - ).stdout().strip().split('\n') + 'find', metacity_asset_dir, '-name', '*.svg', + check: true).stdout().strip().split('\n') metacity_assets_dest = join_paths(theme_dir, 'metacity-1') install_data(metacity_svg_data, install_dir: metacity_assets_dest) diff --git a/test-sucharu b/test-sucharu index a166416e..03c2923c 100755 --- a/test-sucharu +++ b/test-sucharu @@ -3,8 +3,8 @@ rm -rf ~/.local/share/themes/Sucharu* meson setup -Dprefix=$HOME/.local builddir -meson compile -C builddir -meson install -C builddir +meson compile -C builddir --verbose +meson install -C builddir # --dry-run # remove build directory rm -rf builddir