Repository: qutebrowser/qutebrowser

Issue:
Consider alpha channel in utils.interpolate_color
Setting this option in following way, alpha channel value is ignored.
c.colors.tabs.indicator.stop = "rgba(0, 255, 0, 0.8)"



Discussion:
This happens because `utils.interpolate_color` currently [ignores the alpha value](https://github.com/qutebrowser/qutebrowser/blob/master/qutebrowser/utils/utils.py#L236-L287) - marking this as easy because it should be a good first issue for new contributors!

To fix this, it would need to also pass the different alpha values to `_get_color_percentage`, and that would also interpolate that value. Also, a test should be added to the [respective unit tests](https://github.com/qutebrowser/qutebrowser/blob/v1.14.0/tests/unit/utils/test_utils.py#L164).

Finally, it would be good to make `interpolate_color` a bit more readable by renaming variables like `a_c1`, `a_c2` and `a_c3` into something like `r1`, `g1` and `b1` (and `b_c1`, `b_c2` and `b_c3` into `r2`, `g2`, and `b2`) - same scheme for other color systems (HSL/HSV) as well.
Hello! I would like to work on this issue, If that's okay. :)
@duthades Absolutely, please go ahead and feel free to ask if you get stuck somewhere!
> To fix this, it would need to also pass the different alpha values to _get_color_percentage, and that would also interpolate that value. Also, a test should be added to the respective unit tests.

@The-Compiler Test for each colorspace (RGBA, HSVA, HSLA) is needed or just one case (RGBA) is alright?
@duthades If you write a test which only verifies that the alpha component has the correct value (as we have tests for the others already anyways), you should be able to do something like in `test_0_100` - i.e., add a `@pytest.mark.parametrize('colorspace', [QColor.Rgb, QColor.Hsv, QColor.Hsl])` decorator, to have one test testing all of them at once. Relevant docs: [Parametrizing tests — pytest documentation](https://docs.pytest.org/en/stable/example/parametrize.html)

Resolving patch:
diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py
--- a/qutebrowser/utils/utils.py
+++ b/qutebrowser/utils/utils.py
@@ -211,27 +211,30 @@ def resource_filename(filename: str) -> str:
     return pkg_resources.resource_filename(qutebrowser.__name__, filename)
 
 
-def _get_color_percentage(a_c1: int, a_c2: int, a_c3:
-                          int, b_c1: int, b_c2: int, b_c3: int,
-                          percent: int) -> Tuple[int, int, int]:
+def _get_color_percentage(a_c1: int, a_c2: int, a_c3: int, a_alpha: int,
+                          b_c1: int, b_c2: int, b_c3: int, b_alpha: int,
+                          percent: int) -> Tuple[int, int, int, int]:
     """Get a color which is percent% interpolated between start and end.
 
     Args:
-        a_c1, a_c2, a_c3: Start color components (R, G, B / H, S, V / H, S, L)
-        b_c1, b_c2, b_c3: End color components (R, G, B / H, S, V / H, S, L)
+        a_c1, a_c2, a_c3, a_alpha : Start color components (R, G, B, A / H, S, V, A /
+                                                            H, S, L, A)
+        b_c1, b_c2, b_c3, b_alpha : End color components (R, G, B, A / H, S, V, A /
+                                                          H, S, L, A)
         percent: Percentage to interpolate, 0-100.
                  0: Start color will be returned.
                  100: End color will be returned.
 
     Return:
-        A (c1, c2, c3) tuple with the interpolated color components.
+        A (c1, c2, c3, alpha) tuple with the interpolated color components.
     """
     if not 0 <= percent <= 100:
         raise ValueError("percent needs to be between 0 and 100!")
     out_c1 = round(a_c1 + (b_c1 - a_c1) * percent / 100)
     out_c2 = round(a_c2 + (b_c2 - a_c2) * percent / 100)
     out_c3 = round(a_c3 + (b_c3 - a_c3) * percent / 100)
-    return (out_c1, out_c2, out_c3)
+    out_alpha = round(a_alpha + (b_alpha - a_alpha) * percent / 100)
+    return (out_c1, out_c2, out_c3, out_alpha)
 
 
 def interpolate_color(
@@ -264,21 +267,21 @@ def interpolate_color(
 
     out = QColor()
     if colorspace == QColor.Rgb:
-        a_c1, a_c2, a_c3, _alpha = start.getRgb()
-        b_c1, b_c2, b_c3, _alpha = end.getRgb()
-        components = _get_color_percentage(a_c1, a_c2, a_c3, b_c1, b_c2, b_c3,
+        r1, g1, b1, alpha1 = start.getRgb()
+        r2, g2, b2, alpha2 = end.getRgb()
+        components = _get_color_percentage(r1, g1, b1, alpha1, r2, g2, b2, alpha2,
                                            percent)
         out.setRgb(*components)
     elif colorspace == QColor.Hsv:
-        a_c1, a_c2, a_c3, _alpha = start.getHsv()
-        b_c1, b_c2, b_c3, _alpha = end.getHsv()
-        components = _get_color_percentage(a_c1, a_c2, a_c3, b_c1, b_c2, b_c3,
+        h1, s1, v1, alpha1 = start.getHsv()
+        h2, s2, v2, alpha2 = end.getHsv()
+        components = _get_color_percentage(h1, s1, v1, alpha1, h2, s2, v2, alpha2,
                                            percent)
         out.setHsv(*components)
     elif colorspace == QColor.Hsl:
-        a_c1, a_c2, a_c3, _alpha = start.getHsl()
-        b_c1, b_c2, b_c3, _alpha = end.getHsl()
-        components = _get_color_percentage(a_c1, a_c2, a_c3, b_c1, b_c2, b_c3,
+        h1, s1, l1, alpha1 = start.getHsl()
+        h2, s2, l2, alpha2 = end.getHsl()
+        components = _get_color_percentage(h1, s1, l1, alpha1, h2, s2, l2, alpha2,
                                            percent)
         out.setHsl(*components)
     else:


Test patch:
diff --git a/tests/unit/utils/test_utils.py b/tests/unit/utils/test_utils.py
--- a/tests/unit/utils/test_utils.py
+++ b/tests/unit/utils/test_utils.py
@@ -242,6 +242,16 @@ def test_interpolation_hsl(self):
         expected.setHsl(0, 30, 150)
         assert Color(color) == expected
 
+    @pytest.mark.parametrize('colorspace', [QColor.Rgb, QColor.Hsv,
+                                            QColor.Hsl])
+    def test_interpolation_alpha(self, colorspace):
+        """Test interpolation of colorspace's alpha."""
+        start = Color(0, 0, 0, 30)
+        stop = Color(0, 0, 0, 100)
+        color = utils.interpolate_color(start, stop, 50, colorspace)
+        expected = Color(0, 0, 0, 65)
+        assert Color(color) == expected
+
     @pytest.mark.parametrize('percentage, expected', [
         (0, (0, 0, 0)),
         (99, (0, 0, 0)),