Repository: qtile/qtile

Issue:
Scaled BatteryIcon has vertical offset from middle of bar 
### The issue:

When I use the BatteryIcon widget with a scaling that's > 1.0, it seems like the icon gets shifted upwards from the middle of the bar, which messes with the alignment of other icons. 

The following widget method works correctly,
```    
widget.BatteryIcon(
    theme_path=home / ".config/qtile/battery-icons/",
    update_interval=10,
    scale=1.0,
),
```
![Screenshot from 2022-12-07 16-26-18](https://user-images.githubusercontent.com/5190106/206208459-d97de3e2-8e55-4db9-842d-ac76cd0e1d75.png)

But when I change the scale (to 1.4 for example), the following happens:

![Screenshot from 2022-12-07 16-28-17](https://user-images.githubusercontent.com/5190106/206208670-bdb6f7d8-e4fa-4126-8d6a-dd94923e191c.png)

Now the icon size is more consistent, but as you can see the icon is not aligned with the systray's nm-applet icon. 

Is there an easy way to solve this, so that the icon can be scaled down but still sit in the middle of the bar (vertically)? I naively tried to pass some extra padding or margin arguments to the widget, but that didn't work. I then looked at the source code of the BatteryIcon widget, and tried to edit the following method (which I thought was relevant):

```
    def draw(self) -> None:
        self.drawer.clear(self.background or self.bar.background)
        self.drawer.ctx.set_source(self.surfaces[self.current_icon])
        self.drawer.ctx.paint()
        self.drawer.draw(offsetx=self.offset, offsety=self.offsety, width=self.length)
```
by changing the value of the `offsety` argument in the last line. This sort of worked, but it seems like the widget border leaves some region at the top of the bar that is not of the same colour as the rest of the widget background.

![Screenshot from 2022-12-07 16-23-39](https://user-images.githubusercontent.com/5190106/206210194-2f0cee66-c216-476d-a36e-02dc9a831f4d.png)

It seems like there should be a solution to this, but I'm not very familiar with how this all works under the hood. If someone could please take a look at it, or show how to correct it, that would be great! 

Thanks

`qtile --version`:
0.22.1

`qtile-extras` in case it's relevant:
qtile-extras-git r212.f93534b-1



### Required:

- [X] I have searched past issues to see if this bug has already been reported.


Discussion:

Resolving patch:
diff --git a/libqtile/widget/battery.py b/libqtile/widget/battery.py
--- a/libqtile/widget/battery.py
+++ b/libqtile/widget/battery.py
@@ -486,7 +486,7 @@ def __init__(self, **config) -> None:
         self.length_type = bar.STATIC
         self.length = 0
         self.image_padding = 0
-        self.surfaces: dict[str, Img] = {}
+        self.images: dict[str, Img] = {}
         self.current_icon = "battery-missing"
 
         self._battery = self._load_battery(**config)
@@ -518,7 +518,7 @@ def setup_images(self) -> None:
             img.resize(height=new_height)
             if img.width > self.length:
                 self.length = int(img.width + self.image_padding * 2)
-            self.surfaces[key] = img.pattern
+            self.images[key] = img
 
     def update(self) -> None:
         status = self._battery.update_status()
@@ -529,8 +529,12 @@ def update(self) -> None:
 
     def draw(self) -> None:
         self.drawer.clear(self.background or self.bar.background)
-        self.drawer.ctx.set_source(self.surfaces[self.current_icon])
+        image = self.images[self.current_icon]
+        self.drawer.ctx.save()
+        self.drawer.ctx.translate(0, (self.bar.height - image.height) // 2)
+        self.drawer.ctx.set_source(image.pattern)
         self.drawer.ctx.paint()
+        self.drawer.ctx.restore()
         self.drawer.draw(offsetx=self.offset, offsety=self.offsety, width=self.length)
 
     @staticmethod


Test patch:
diff --git a/test/widgets/test_battery.py b/test/widgets/test_battery.py
--- a/test/widgets/test_battery.py
+++ b/test/widgets/test_battery.py
@@ -1,4 +1,3 @@
-import cairocffi
 import pytest
 
 from libqtile import images
@@ -193,9 +192,9 @@ def test_images_good(tmpdir, fake_bar, svg_img_as_pypath):
     batt.fontsize = 12
     batt.bar = fake_bar
     batt.setup_images()
-    assert len(batt.surfaces) == len(BatteryIcon.icon_names)
-    for name, surfpat in batt.surfaces.items():
-        assert isinstance(surfpat, cairocffi.SurfacePattern)
+    assert len(batt.images) == len(BatteryIcon.icon_names)
+    for name, img in batt.images.items():
+        assert isinstance(img, images.Img)
 
 
 def test_images_default(fake_bar):
@@ -207,9 +206,9 @@ def test_images_default(fake_bar):
     batt.fontsize = 12
     batt.bar = fake_bar
     batt.setup_images()
-    assert len(batt.surfaces) == len(BatteryIcon.icon_names)
-    for name, surfpat in batt.surfaces.items():
-        assert isinstance(surfpat, cairocffi.SurfacePattern)
+    assert len(batt.images) == len(BatteryIcon.icon_names)
+    for name, img in batt.images.items():
+        assert isinstance(img, images.Img)
 
 
 def test_battery_background(fake_qtile, fake_window, monkeypatch):