Skip to content

Commit

Permalink
Make GroupBox2 compatible with vertical bars
Browse files Browse the repository at this point in the history
  • Loading branch information
elParaguayo committed Nov 14, 2024
1 parent 91af5eb commit fdf85d0
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
2024-11-14: [FEATURE] Enable support for vertical bars for `GroupBox2`
2024-11-03: [FEATURE] Add `ImageDecoration` for widgets
2024-10-19: [RELEASE] v0.29.0 release - compatible with qtile 0.29.0
2024-08-23: [FEATURE] Add `GradientDecoration` for widgets
Expand Down
92 changes: 71 additions & 21 deletions qtile_extras/widget/groupbox2.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ def __init__(
self.group_name: str | None = None
self.func: Callable[[GroupBoxRule, Box], bool] | None = None
self.always_check = False
self._inverted = False

size: int | Sentinel | None

Expand Down Expand Up @@ -190,7 +191,7 @@ def when(

return self

def match(self, box: Box) -> bool:
def _match(self, box: Box) -> bool:
"""Returns True if box conditions match rule criteria."""
if not self.screen & ScreenRule.UNSET:
if not box.screen & self.screen:
Expand All @@ -214,6 +215,13 @@ def match(self, box: Box) -> bool:

return True

def match(self, box: Box) -> bool:
matched = self._match(box)
if not self._inverted:
return matched

return not matched

def force_check(self):
self.always_check = True
return self
Expand All @@ -226,11 +234,16 @@ def reset(self, attr: str) -> None:

def __repr__(self) -> str:
"""Short representation of rule instance."""
inverted = "_not" if self._inverted else ""
output = describe_attributes(self, GroupBoxRule.attrs, lambda x: x is not SENTINEL)
when = describe_attributes(
self, ["screen", "focused", "occupied", "urgent", "group_name", "func"], filter_attrs
)
return f"<GroupBoxRule format({output}) when({when})>"
return f"<GroupBoxRule format({output}) when{inverted}({when})>"

def __invert__(self):
self._inverted = not self._inverted
return self


class Box:
Expand All @@ -240,7 +253,7 @@ class Box:
fontshadow: bool | None
markup: bool
padding_x: int
paddint_y: int
padding_y: int
rules: list[GroupBoxRule]
margin_x: int
margin_y: int
Expand Down Expand Up @@ -386,7 +399,10 @@ def _load_image(self, filename: str, scale=True) -> bool:
return False

if scale:
img.resize(height=self.bar.height - 2 * self.margin_y)
if self.horizontal:
img.resize(height=self.bar.height - 2 * self.margin_y)
else:
img.resize(width=self.bar.width - 2 * self.margin_x)
IMAGE_CACHE[filename] = img

return True
Expand All @@ -402,6 +418,10 @@ def get_image(self, filename: str, scale=True) -> Img | None:
def rule_attrs(self) -> list[str]:
return GroupBoxRule.attrs

@property
def horizontal(self) -> bool:
return self.bar.horizontal

def _reset_format(self) -> None:
"""Clears all formatting for the box."""
# Use ``SENTINEL`` instance as default value so we can allow a value
Expand All @@ -424,16 +444,33 @@ def size(self) -> int:
del self.layout.width
self.layout.text = self.text

if not self.horizontal:
self.layout.width = self.bar.width

if self.visible is False:
return 0

if self.box_size:
return self.box_size

elif self.image and self.image in IMAGE_CACHE:
return IMAGE_CACHE[self.image].width + 2 * self.margin_x
if self.horizontal:
return IMAGE_CACHE[self.image].width + 2 * self.margin_x
else:
return IMAGE_CACHE[self.image].height + 2 * self.margin_y

return self.layout.width + 2 * self.padding_x
if self.horizontal:
return self.layout.width + 2 * self.padding_x
else:
return self.layout.height + 2 * self.padding_y

@property
def bottom(self):
return self.bar.height if self.horizontal else self.size

@property
def right(self):
return self.size if self.horizontal else self.bar.width

@property
def has_block(self) -> bool:
Expand All @@ -454,8 +491,8 @@ def draw_block(self) -> None:
ctx.rectangle(
self.margin_x,
self.margin_y,
self.size - 2 * self.margin_x,
self.bar.height - 2 * self.margin_y,
(self.size if self.horizontal else self.bar.width) - 2 * self.margin_x,
(self.bar.height if self.horizontal else self.size) - 2 * self.margin_y,
)

# If not, we need to do rounded corers
Expand All @@ -468,8 +505,8 @@ def draw_block(self) -> None:
delta = radius + 1
x = self.margin_x
y = self.margin_y
width = self.size - 2 * self.margin_x
height = self.bar.height - 2 * self.margin_y
width = (self.size if self.horizontal else self.bar.width) - 2 * self.margin_x
height = (self.bar.height if self.horizontal else self.size) - 2 * self.margin_y
ctx.arc(x + width - delta, y + delta, radius, -90 * degrees, 0 * degrees)
ctx.arc(x + width - delta, y + height - delta, radius, 0 * degrees, 90 * degrees)
ctx.arc(x + delta, y + height - delta, radius, 90 * degrees, 180 * degrees)
Expand Down Expand Up @@ -499,10 +536,10 @@ def _draw_line(self, offset, vertical=False) -> None:
"""
if vertical:
start = (offset, 0)
end = (0, self.bar.height)
end = (0, self.bottom)
else:
start = (0, offset)
end = (self.size, 0)
end = (self.right, 0)

ctx = self.drawer.ctx
ctx.save()
Expand All @@ -523,13 +560,13 @@ def draw_line(self, line_width: int) -> None:
self._draw_line(line_width // 2)

if self.line_position & LinePosition.BOTTOM:
self._draw_line(self.bar.height - line_width // 2)
self._draw_line(self.bottom - line_width // 2)

if self.line_position & LinePosition.LEFT:
self._draw_line(line_width // 2, vertical=True)

if self.line_position & LinePosition.RIGHT:
self._draw_line(self.size - line_width // 2, vertical=True)
self._draw_line(self.right - line_width // 2, vertical=True)

def draw_image(self) -> None:
"""Draws the image, offset by margin_x and margin_y."""
Expand All @@ -542,21 +579,27 @@ def draw_image(self) -> None:

ctx = self.drawer.ctx
ctx.save()
ctx.translate((self.size - img.width) // 2, self.margin_y)
if self.horizontal:
ctx.translate((self.size - img.width) // 2, self.margin_y)
else:
ctx.translate(self.margin_x, (self.size - img.height) // 2)
ctx.set_source(img.pattern)
ctx.paint()
ctx.restore()

def draw_text(self) -> None:
"""Draws text, centered vertically."""
self.layout.colour = self.text_colour
self.layout.draw(self.padding_x, (self.bar.height - self.layout.height) // 2)
if self.horizontal:
self.layout.draw(self.padding_x, (self.bar.height - self.layout.height) // 2)
else:
self.layout.draw(0, self.padding_y)

def draw(self, offset) -> None:
"""Main method to draw all formatting."""
self.drawer.ctx.save()

self.drawer.ctx.translate(offset, 0)
self.drawer.ctx.translate(*offset)

if self.has_block:
self.draw_block()
Expand Down Expand Up @@ -610,6 +653,10 @@ class GroupBox2(base._Widget, base.MarginMixin, base.PaddingMixin):
* Whether the group name matches a given string
* Whether a user-defined function returns True
Rules can be inverted by using the ``~`` operator. For example, to apply to rule when the group is not
on the current screen, you can write ``~GroupBoxRule(text_colour="888").when(screen=GroupBoxRule.SCREEN_THIS)``.
This is expected to be of limited use but may provide finer control in some circumstances.
Rules are only rechecked when there a change to one of the following properties of the groups:
* Whether the group is focused
Expand Down Expand Up @@ -828,7 +875,7 @@ def set_label(rule, box):

_experimental = True

orientations = base.ORIENTATION_HORIZONTAL
orientations = base.ORIENTATION_BOTH

defaults: list[tuple[str, Any, str]] = [
(
Expand Down Expand Up @@ -932,6 +979,7 @@ def box_config(self):
"fontshadow",
"markup",
"padding_x",
"padding_y",
"rules",
"margin_x",
"margin_y",
Expand All @@ -946,23 +994,25 @@ def draw(self):
for box in self.boxes:
if box.visible is False:
continue
box.draw(offset)
box.draw((offset, 0) if self.bar.horizontal else (0, offset))
offset += box.size

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

def button_press(self, x, y, button):
self.click_pos = x
self.click_pos = x, y
base._Widget.button_press(self, x, y, button)

def get_clicked_group(self):
group = None
offset = 0
for box in self.boxes:
offset += box.size
if self.click_pos <= offset:
if (self.bar.horizontal and self.click_pos[0] <= offset) or (
not self.bar.horizontal and self.click_pos[1] <= offset
):
group = box.group
break
return group
Expand Down

0 comments on commit fdf85d0

Please sign in to comment.