Skip to content

Commit

Permalink
Move wifi render to mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
elParaguayo committed Dec 21, 2023
1 parent f235a51 commit e3de8d7
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 66 deletions.
62 changes: 54 additions & 8 deletions qtile_extras/widget/iwd.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from libqtile.widget import base

from qtile_extras.popup.menu import PopupMenuItem, PopupMenuSeparator
from qtile_extras.widget.mixins import MenuMixin
from qtile_extras.widget.mixins import GraphicalWifiMixin, MenuMixin

IWD_SERVICE = "net.connman.iwd"
IWD_DEVICE = IWD_SERVICE + ".Device"
Expand Down Expand Up @@ -240,7 +240,7 @@ async def connect(self):
await self.network.call_connect()


class IWD(base._TextBox, base.MarginMixin, MenuMixin):
class IWD(base._TextBox, base.MarginMixin, MenuMixin, GraphicalWifiMixin):
"""
This widget provides information about your wireless connection using iwd.
Expand Down Expand Up @@ -268,14 +268,18 @@ class IWD(base._TextBox, base.MarginMixin, MenuMixin):
"Additional args to pass to password entry command.",
),
("format", "{ssid} ({quality}%)", "Text format. Available fields: ssid, rssi, quality"),
("show_text", True, "Displays text in bar."),
("show_image", False, "Shows a graphical representation of signal strength."),
]

def __init__(self, **config):
base._TextBox.__init__(self, **config)
self.add_defaults(MenuMixin.defaults)
self.add_defaults(GraphicalWifiMixin.defaults)
self.add_defaults(IWD.defaults)
self.add_defaults(base.MarginMixin.defaults)
MenuMixin.__init__(self, **config)
GraphicalWifiMixin.__init__(self)
self.bus = None
self.device = None
self.networks = {}
Expand All @@ -286,9 +290,26 @@ def __init__(self, **config):
self._setting_up = False
self.add_callbacks({"Button1": self.do_menu})
self._can_connect = False
self.percentage = 0

def _configure(self, qtile, bar):
base._TextBox._configure(self, qtile, bar)
self.set_wifi_sizes()

def calculate_length(self):
width = 0
text_width = base._TextBox.calculate_length(self)
image_width = self.wifi_width + 2 * self.actual_padding

if self.show_text:
width += text_width

if self.show_image:
width += image_width
if self.show_text:
width -= self.actual_padding

return width

async def _config_async(self):
await self._connect()
Expand Down Expand Up @@ -474,19 +495,44 @@ def get_stats(self):
task.add_done_callback(self.refresh)

def refresh(self, *args):
old_width = self.layout.width

if self.device is None:
self.update("Error")
return
self.text = "Error"
self.percentage = 0

self.update(
self.format.format(
else:
self.text = self.format.format(
ssid=self.networks[self.device.connected_network].name,
quality=self.device.quality,
rssi=self.device.rssi,
),
)
)
self.percentage = self.device.quality / 100.0

if old_width != self.layout.width:
self.bar.draw()
else:
self.draw()

self.timeout_add(self.update_interval, self.get_stats)

def draw(self):
if not self.can_draw:
return

self.drawer.clear(self.background or self.bar.background)
offset = self.wifi_padding_x
if self.show_image:
self.draw_wifi(self.percentage)
offset += self.wifi_width + self.wifi_padding_x

if self.show_text:
self.layout.draw(offset, int(self.bar.height / 2.0 - self.layout.height / 2.0) + 1)

self.drawer.draw(
offsetx=self.offsetx, offsety=self.offsety, width=self.width, height=self.height
)

def do_menu(self):
menu_items = []

Expand Down
89 changes: 89 additions & 0 deletions qtile_extras/widget/mixins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import math
from copy import deepcopy
from typing import TYPE_CHECKING

Expand All @@ -31,6 +32,13 @@
from typing import Any, Callable # noqa: F401


PI = math.pi


def to_rads(degrees):
return degrees * PI / 180.0


class _BaseMixin:
"""Base class to help docs only show mixins."""

Expand Down Expand Up @@ -513,3 +521,84 @@ def draw_bar(
layout.draw(0, 0)

self.drawer.ctx.restore()


class GraphicalWifiMixin(_BaseMixin):
defaults = [
("wifi_arc", 75, "Angle of arc in degrees."),
("wifi_rectangle_width", 5, "Width of rectangle in pixels."),
("wifi_shape", "arc", "'arc' or 'rectangle'"),
]

def __init__(self):
self.wifi_width = 0

def set_wifi_sizes(self):
self.wifi_padding_x = getattr(self, "padding_x", getattr(self, "padding", 0))
self.wifi_padding_y = getattr(self, "padding_y", getattr(self, "padding", 0))
self.wifi_height = self.bar.height - (self.wifi_padding_y * 2)
width_ratio = math.sin(to_rads(self.wifi_arc / 2))
if self.wifi_shape == "arc":
self.wifi_width = (self.wifi_height * width_ratio) * 2
self.wifi_width = math.ceil(self.wifi_width)
else:
self.wifi_width = self.wifi_rectangle_width

self.icon_size = self.wifi_height

def draw_wifi(self, percentage, foreground="ffffff", background="777777"):
if self.wifi_shape == "arc":
func = self._draw_wifi_arc
else:
func = self._draw_wifi_rectangle

func(percentage, foreground, background)

def _draw_wifi_arc(self, percentage, foreground, background):
offset = self.wifi_padding_x

half_arc = self.wifi_arc / 2
x_offset = int(self.wifi_height * math.sin(to_rads(half_arc)))

self.drawer.ctx.new_sub_path()

self.drawer.ctx.move_to(
self.wifi_padding_x + x_offset, self.wifi_padding_y + self.wifi_height
)
self.drawer.ctx.arc(
offset + x_offset,
self.wifi_padding_y + self.wifi_height,
self.wifi_height,
to_rads(270 - half_arc),
to_rads(270 + half_arc),
)
self.drawer.set_source_rgb(background)
self.drawer.ctx.fill()

self.drawer.ctx.new_sub_path()
self.drawer.ctx.move_to(offset + x_offset, self.wifi_padding_y + self.wifi_height)
self.drawer.ctx.arc(
offset + x_offset,
self.wifi_padding_y + self.wifi_height,
self.wifi_height * percentage,
to_rads(270 - half_arc),
to_rads(270 + half_arc),
)
self.drawer.set_source_rgb(foreground)
self.drawer.ctx.fill()

def _draw_wifi_rectangle(self, percentage, foreground, background):
ctx = self.drawer.ctx
ctx.save()
ctx.translate(self.wifi_padding_x, self.wifi_padding_y)
ctx.rectangle(0, 0, self.wifi_width, self.wifi_height)
self.drawer.set_source_rgb(background)
ctx.fill()

ctx.rectangle(
0, self.wifi_height * (1 - percentage), self.wifi_width, self.wifi_height * percentage
)
self.drawer.set_source_rgb(foreground)
ctx.fill()

ctx.restore()
74 changes: 16 additions & 58 deletions qtile_extras/widget/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import math
import socket
from contextlib import contextmanager

Expand All @@ -27,13 +26,7 @@
from libqtile.widget import base
from libqtile.widget.wlan import get_status

PI = math.pi

WIFI_ARC_DEGREES = 75


def to_rads(degrees):
return degrees * PI / 180.0
from qtile_extras.widget.mixins import GraphicalWifiMixin


@contextmanager
Expand All @@ -45,7 +38,7 @@ def socket_context(*args, **kwargs):
s.close()


class WiFiIcon(base._Widget, base.PaddingMixin):
class WiFiIcon(base._Widget, base.PaddingMixin, GraphicalWifiMixin):
"""
An simple graphical widget that shows WiFi status.
Expand All @@ -64,7 +57,6 @@ class WiFiIcon(base._Widget, base.PaddingMixin):
("active_colour", "ffffff", "Colour for wifi strength."),
("inactive_colour", "666666", "Colour for wifi background."),
("update_interval", 1, "Polling interval in secs."),
("wifi_arc", 75, "Width of arc in degrees."),
("interface", "wlan0", "Name of wifi interface."),
(
"expanded_timeout",
Expand Down Expand Up @@ -98,6 +90,8 @@ def __init__(self, **config):
base._Widget.__init__(self, bar.CALCULATED, **config)
self.add_defaults(WiFiIcon.defaults)
self.add_defaults(base.PaddingMixin.defaults)
self.add_defaults(GraphicalWifiMixin.defaults)
GraphicalWifiMixin.__init__(self)

self.add_callbacks({"Button1": self.show_text})

Expand All @@ -122,7 +116,7 @@ def __init__(self, **config):
def _configure(self, qtile, bar):
base._Widget._configure(self, qtile, bar)

self.set_sizes()
self.set_wifi_sizes()

if self.update_interval:
self.timeout_add(self.update_interval, self.loop)
Expand Down Expand Up @@ -166,61 +160,25 @@ def update(self):
except Exception:
logger.exception("Couldn't get wifi info.")

def draw_wifi(self, percentage):
offset = self.padding_x

half_arc = self.wifi_arc / 2
x_offset = int(self.wifi_height * math.sin(to_rads(half_arc)))

self.drawer.ctx.new_sub_path()

self.drawer.ctx.move_to(self.padding_x + x_offset, self.padding_y + self.wifi_height)
self.drawer.ctx.arc(
offset + x_offset,
self.padding_y + self.wifi_height,
self.wifi_height,
to_rads(270 - half_arc),
to_rads(270 + half_arc),
)
self.drawer.set_source_rgb(self.inactive_colour)
self.drawer.ctx.fill()

self.drawer.ctx.new_sub_path()
self.drawer.ctx.move_to(offset + x_offset, self.padding_y + self.wifi_height)
self.drawer.ctx.arc(
offset + x_offset,
self.padding_y + self.wifi_height,
self.wifi_height * percentage,
to_rads(270 - half_arc),
to_rads(270 + half_arc),
)
self.drawer.set_source_rgb(
self.active_colour if self.is_connected else self.disconnected_colour
)
self.drawer.ctx.fill()

offset += self.wifi_width + self.padding_x

if self._show_text:
layout = self.get_wifi_text()
layout.draw(offset, int((self.bar.height - layout.height) / 2))
def draw_wifi_text(self):
offset = self.wifi_width + 2 * self.wifi_padding_x
layout = self.get_wifi_text()
layout.draw(offset, int((self.bar.height - layout.height) / 2))

def draw(self):
if not self.configured:
return

self.drawer.clear(self.background or self.bar.background)
self.draw_wifi(self.percent)
self.draw_wifi(
self.percent,
foreground=self.active_colour if self.is_connected else self.disconnected_colour,
background=self.inactive_colour,
)
if self._show_text:
self.draw_wifi_text()
self.drawer.draw(offsetx=self.offset, offsety=self.offsety, width=self.length)

def set_sizes(self):
self.wifi_height = self.bar.height - (self.padding_y * 2)
width_ratio = math.sin(to_rads(self.wifi_arc / 2))
self.wifi_width = (self.wifi_height * width_ratio) * 2
self.wifi_width = math.ceil(self.wifi_width)

self.icon_size = self.wifi_height

def get_wifi_text(self, size_only=False):
text = f"{self.essid} ({self.percent * 100:.0f}%)"

Expand Down

0 comments on commit e3de8d7

Please sign in to comment.