My collection of plugins for the Qtile window manager.
git clone https://mcol.xyz/code/qtools
Log | Files | Refs | README

commit 94e9f6b814c9e96ed81993dca0f85e3e52e5e56f
parent cd06a15654d2b106afdbacf186a3663661d68c67
Author: mcol <mcol@posteo.net>
Date:   Sat, 25 Jan 2020 00:07:52 +0000

create generalised base class for popup windows

Diffstat:
Mqtools/__init__.py | 138++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 133 insertions(+), 5 deletions(-)

diff --git a/qtools/__init__.py b/qtools/__init__.py @@ -7,11 +7,14 @@ import gi gi.require_version('Notify', '0.7') from gi.repository import Notify -from libqtile.configurable import Configurable -from libqtile.command import lazy +from xcffib.xproto import StackMode +from libqtile import configurable, pangocffi, window +from libqtile.lazy import lazy +from libqtile.drawer import Drawer -class Notifier(Configurable): + +class Notifier(configurable.Configurable): """ This is a base class for classes with methods that are to be executed upon key presses and that generate pop-up notifications. @@ -28,7 +31,7 @@ class Notifier(Configurable): Notifier._is_initted = True Notify.init('Qtile') - Configurable.__init__(self, **config) + configurable.Configurable.__init__(self, **config) self.add_defaults(Notifier.defaults) self.notifier = Notify.Notification.new( config.get('summary', 'Notifier'), '' @@ -42,7 +45,7 @@ class Notifier(Configurable): """ if name.startswith('lazy_'): return lazy.function(getattr(self, name[5:])) - return Configurable.__getattr__(self, name) + return configurable.Configurable.__getattr__(self, name) @property def timeout(self): @@ -61,3 +64,128 @@ class Notifier(Configurable): def hide(self): self.notifier.hide() + + +ALIGNMENTS = { + 'left': pangocffi.pango.PANGO_ALIGN_LEFT, + 'center': pangocffi.pango.PANGO_ALIGN_CENTER, + 'right': pangocffi.pango.PANGO_ALIGN_RIGHT, +} + + +class Popup(configurable.Configurable): + """ + This base class can be used to create popup windows for a variety of purposes. + """ + defaults = [ + ('opacity', 1.0, 'Opacity of notifications.'), + ('foreground', '#ffffff', 'Color of text.'), + ('background', '#111111', 'Background color.'), + ('border', '#111111', 'Border color.'), + ('border_width', 4, 'Line width of drawn borders.'), + ('corner_radius', None, 'Corner radius for round corners, or None.'), + ('font', 'sans', 'Font used in notifications.'), + ('fontsize', 14, 'Size of font.'), + ('fontshadow', None, 'Color for text shadows, or None for no shadows.'), + ('padding', None, 'Padding at sides of text.'), + ('text_alignment', 'left', 'Text alignment: left, center or right.'), + ] + + def __init__(self, qtile, x=50, y=50, width=256, height=64, **config): + configurable.Configurable.__init__(self, **config) + self.add_defaults(Popup.defaults) + self.qtile = qtile + + win = qtile.conn.create_window(x, y, width, height) + win.set_property("QTILE_INTERNAL", 1) + self.win = window.Internal(win, qtile) + self.win.opacity = self.opacity + self.drawer = Drawer( + self.qtile, self.win.window.wid, width, height, + ) + self.layout = self.drawer.textlayout( + text='', + colour=self.foreground, + font_family=self.font, + font_size=self.fontsize, + font_shadow=self.fontshadow, + wrap=True, + markup=True, + ) + self.layout.layout.set_alignment(ALIGNMENTS[self.text_alignment]) + + if self.border_width: + self.win.window.configure(borderwidth=self.border_width) + if self.corner_radius: + self.win.window.round_corners( + width, height, self.corner_radius, self.border_width, + ) + + self.win.handle_Expose = self._handle_Expose + self.win.handle_KeyPress = self._handle_KeyPress + self.win.handle_ButtonPress = self._handle_ButtonPress + self.qtile.windows_map[self.win.window.wid] = self.win + + self.x = self.win.x + self.y = self.win.y + self.width = self.win.width + self.height = self.win.height + + def _handle_Expose(self, e): + pass + + def _handle_KeyPress(self, event): + pass + + def _handle_ButtonPress(self, event): + if event.detail == 1: + self.hide() + + @property + def text(self): + return self.layout.text + + @text.setter + def text(self, value): + self.layout.text = value + + @property + def foreground(self): + return self._foreground + + @foreground.setter + def foreground(self, value): + self._foreground = value + if hasattr(self, 'layout'): + self.layout.colour = value + + def set_border(self, color): + self.win.window.set_attribute(borderpixel=color) + + def clear(self): + self.drawer.clear(self.background) + + def draw_text(self): + self.layout.draw( + self.padding, + (self.win.height - self.layout.height) / 2, + ) + + def draw_window(self): + self.drawer.draw() + + def place(self): + self.win.place( + self.x, self.y, self.width, self.height, + self.border_width, self.border, above=True + ) + + def unhide(self): + self.win.unhide() + self.win.window.configure(stackmode=StackMode.Above) + + def hide(self): + self.win.hide() + + def kill(self): + self.win.kill()