From: mar77i Date: Wed, 18 Dec 2024 01:46:37 +0000 (+0100) Subject: consolidate component interactions X-Git-Url: https://git.mar77i.info/?a=commitdiff_plain;h=5e06f90567ee00cbb6cb2d375230991ecd93da32;p=zenbook_conf consolidate component interactions --- diff --git a/ui.py b/ui.py index c70307c..48ee7cd 100755 --- a/ui.py +++ b/ui.py @@ -6,8 +6,6 @@ from colorsys import hsv_to_rgb import pygame -from bluetooth import BluetoothConf - tau = 2 * pi @@ -32,7 +30,8 @@ class Switch: MOVE_FOR_SEC = 1 EASE = staticmethod(ease_in_out_elastic((5 ** .5 - 1) / 2)) - def __init__(self, rect, update_callback, setting=False): + def __init__(self, parent, rect, update_callback, setting=False): + self.parent = parent self.rect = rect self.update_callback = update_callback if setting is not None and not isinstance(setting, bool): @@ -41,23 +40,8 @@ class Switch: self.moving_since = nan self.flip_again = False - def handle_mousebuttondown(self, ev): - if ev.button == 1 and self.rect.collidepoint(ev.pos): - if self.moving_since is not nan: - self.flip_again = True - else: - offset = self.MOVE_FOR_SEC / 2 if self.setting is None else 0 - self.setting = bool(self.setting) ^ True - self.moving_since = time() - offset - - def update(self, new_value=None): - if new_value is not None and new_value != self.setting: - self.setting = new_value - self.moving_since = time() - return self.moving_since is not nan - - def draw(self, surf): - pygame.draw.rect(surf, "gray", self.rect, 8) + def draw(self): + pygame.draw.rect(self.parent.surf, "gray", self.rect, 8) t = time() if t > self.moving_since + self.MOVE_FOR_SEC: self.update_callback(self.setting) @@ -88,90 +72,123 @@ class Switch: args = (1 / 3, 2 * normalized_current, 0.5 + normalized_current * 0.5) rgb = hsv_to_rgb(*args) pygame.draw.circle( - surf, + self.parent.surf, pygame.Color(*(int(x * 255) for x in rgb)), (base_left + eased_current * movement_width, self.rect.top + base_radius), base_radius ) + def update(self, new_value=None): + if new_value is not None and new_value != self.setting: + self.setting = new_value + self.moving_since = time() + if self.moving_since is not nan: + self.parent.dirty = True + + def handle_mousebuttondown(self, ev): + if ev.button == 1 and self.rect.collidepoint(ev.pos): + if self.moving_since is not nan: + self.flip_again = True + else: + offset = self.MOVE_FOR_SEC / 2 if self.setting is None else 0 + self.setting = bool(self.setting) ^ True + self.moving_since = time() - offset + class Button: - def __init__(self, rect, font, label, callback): + def __init__(self, parent, rect, label, callback): + self.parent = parent self.rect = rect - self.font = font self.label = label self.pushed = False self.callback = callback - def draw(self, surf): + def draw(self): if not self.pushed: - pygame.draw.rect(surf, "gray", self.rect, 8) - fs = self.font.render(self.label, True, "gray") + frame_color = "gray" + fs = self.parent.font.render(self.label, True, "gray") else: - pygame.draw.rect(surf, "darkgray", self.rect) - pygame.draw.rect(surf, "lightgray", self.rect, 4) - fs = self.font.render(self.label, True, "black") + pygame.draw.rect(self.parent.surf, "darkgray", self.rect) + frame_color = "lightgray" + fs = self.parent.font.render(self.label, True, "black") + pygame.draw.rect(self.parent.surf, frame_color, self.rect, 8) fs_size = fs.get_size() center = self.rect.center - surf.blit(fs, (center[0] - fs_size[0] // 2, center[1] - fs_size[1] // 2)) - - def handle_event(self, ev): - if ev.type == pygame.MOUSEBUTTONDOWN: - if ev.button == 1 and self.rect.collidepoint(ev.pos): - self.pushed = True - return True - elif ev.type == pygame.MOUSEBUTTONUP: - if ev.button == 1 and self.pushed and self.rect.collidepoint(ev.pos): - self.pushed = False - self.callback() - return True - elif ev.type == pygame.MOUSEMOTION: - if ev.buttons[0] and self.pushed and not self.rect.collidepoint(ev.pos): - self.pushed = False - return True - return False - - -def main(): - pygame.init() - surf = pygame.display.set_mode((800, 600)) - clock = pygame.time.Clock() - font = pygame.font.Font(None, size=64) - bc = BluetoothConf() - switch = Switch(pygame.Rect((64, 64), (256, 128)), bc.update, bc.conf) - - def cb(): - switch.update(not bc.conf) - bc.update(not bc.conf) - - button = Button(pygame.Rect((64, 256), (384, 128)), font, "Apply", cb) - running = True - dirty = False - while True: - for ev in pygame.event.get(): - if ev.type == pygame.QUIT: - running = False - break - elif ev.type == pygame.WINDOWEXPOSED: - dirty = True - elif ev.type == pygame.KEYDOWN: - if ev.key == pygame.K_ESCAPE: - running = False - break - elif ev.type == pygame.MOUSEBUTTONDOWN: - switch.handle_mousebuttondown(ev) - dirty |= button.handle_event(ev) - if not running: - break - dirty |= switch.update() - if dirty: - surf.fill("black") - switch.draw(surf) - button.draw(surf) - pygame.display.update() - dirty = False - clock.tick(60) - - -if __name__ == "__main__": - main() + self.parent.surf.blit( + fs, (center[0] - fs_size[0] // 2, center[1] - fs_size[1] // 2) + ) + + def update(self): + pass + + def handle_mousebuttondown(self, ev): + if ev.button == 1 and self.rect.collidepoint(ev.pos): + self.pushed = True + self.parent.dirty = True + + def handle_mousebuttonup(self, ev): + if ev.button == 1 and self.pushed and self.rect.collidepoint(ev.pos): + self.pushed = False + self.callback() + self.parent.dirty = True + + def handle_mousemotion(self, ev): + if not self.pushed: + return + if ev.buttons[0] and not self.rect.collidepoint(ev.pos): + self.pushed = False + self.parent.dirty = True + + +class IconButton: + def __init__(self, parent, name, shape, shape_size, rect): + self.parent = parent + self.name = name + self.shape = shape + self.shape_size = shape_size + self.rect = rect + + def draw(self): + color = "lime " if self.parent.xrandr_conf.is_active(self.name) else "gray" + pygame.draw.rect(self.parent.surf, color, self.rect, 8) + units = (16, 16) + full_size = (units[0] * self.shape_size[0], units[1] * self.shape_size[1]) + center = self.rect.center + self.shape.draw( + self.parent.surf, + (center[0] - full_size[0] // 2, center[1] - full_size[1] // 2), + units, + "white", + ) + + def update(self): + pass + + def handle_mousebuttondown(self, ev): + if not self.rect.collidepoint(ev.pos): + return + self.parent.xrandr_conf.update(self.name) + if self.name != "single": + self.parent.bluetooth_conf.update(True) + self.parent.bt_switch.update(True) + settings_per_device_type = { + "touchpad": self.parent.touch_switch.setting, + "stylus": self.parent.stylus_switch.setting, + } + for device_type, setting in settings_per_device_type.items(): + if setting is not None: + self.parent.xinput_conf.update_by_type(device_type, setting) + self.parent.dirty = True + + +class Icon: + def __init__(self, parent, shape, pos): + self.parent = parent + self.shape = shape + self.pos = pos + + def update(self): + pass + + def draw(self): + self.shape.draw(self.parent.surf, self.pos, (8, 8), "gray") diff --git a/vectors.py b/vectors.py index 679a7c2..c157f79 100755 --- a/vectors.py +++ b/vectors.py @@ -258,6 +258,15 @@ stylus = Shapes( StrokeLine((11, 11), (12, 12), 1), ] ) +bluetooth = Shapes( + [ + StrokeLine((10, 2), (15, 6), 1.5), + StrokeLine((15, 6), (5, 14), 1.5), + StrokeLine((10, 2), (10, 19), 1.5), + StrokeLine((10, 19), (15, 15), 1.5), + StrokeLine((15, 15), (5, 7), 1.5), + ] +) shapes = [ { "shape": laptop_single, @@ -279,6 +288,10 @@ shapes = [ "shape": stylus, "pos": (600, 600), }, + { + "shape": bluetooth, + "pos": (1100, 600), + }, ] diff --git a/zenbook_conf.py b/zenbook_conf.py index afe2abc..5d7479b 100755 --- a/zenbook_conf.py +++ b/zenbook_conf.py @@ -5,31 +5,20 @@ from functools import partial import pygame from bluetooth import BluetoothConf -from ui import Button, Switch -from vectors import laptop_double, laptop_single, laptop_vertical, touchscreen, stylus +from ui import Button, Icon, IconButton, Switch +from vectors import ( + bluetooth, + laptop_double, + laptop_single, + laptop_vertical, + touchscreen, + stylus, +) from xinput import XinputConf from xrandr import XrandrConf class ZenbookConf: - SHAPES = ( - { - "name": "single", - "shape": laptop_single, - "rect": pygame.Rect((68, 68), (416, 416)), - }, - { - "name": "double", - "shape": laptop_double, - "rect": pygame.Rect((568, 68), (416, 416)), - }, - { - "name": "vertical", - "shape": laptop_vertical, - "rect": pygame.Rect((1068, 68), (416, 416)), - }, - ) - def __init__(self): pygame.init() self.surf = pygame.display.set_mode((1536, 1200)) @@ -41,32 +30,76 @@ class ZenbookConf: self.xinput_conf = XinputConf(self.xrandr_conf) self.bluetooth_conf = BluetoothConf() self.current_fps = -1 - self.bt_switch = Switch( + bt_switch = Switch( + self, pygame.Rect((128, 552), (256, 128)), self.bluetooth_conf.update, self.bluetooth_conf.conf ) - self.touch_switch = Switch( + touch_switch = Switch( + self, pygame.Rect((128, 748), (256, 128)), partial(self.xinput_conf.update_by_type, "touchpad"), self.xinput_conf.conf_by_type("touchpad"), ) - self.touch_button = Button( - pygame.Rect((784, 748), (384, 128)), - self.font, - "Re-apply", - partial(self.xinput_conf.reapply_by_type, "touchpad") - ) - self.stylus_switch = Switch( + stylus_switch = Switch( + self, pygame.Rect((128, 944), (256, 128)), partial(self.xinput_conf.update_by_type, "stylus"), self.xinput_conf.conf_by_type("stylus"), ) - self.stylus_button = Button( - pygame.Rect((784, 944), (384, 128)), - self.font, - "Re-apply", - partial(self.xinput_conf.reapply_by_type, "stylus") + self.children = ( + IconButton( + self, + "single", + laptop_single, + (22, 22), + pygame.Rect((68, 68), (416, 416)), + ), + IconButton( + self, + "double", + laptop_double, + (22, 22), + pygame.Rect((568, 68), (416, 416)), + ), + IconButton( + self, + "vertical", + laptop_vertical, + (22, 22), + pygame.Rect((1068, 68), (416, 416)), + ), + bt_switch, + Icon( + self, + bluetooth, + (bt_switch.rect.right + 68, bt_switch.rect.centery - 88), + ), + touch_switch, + Icon( + self, + touchscreen, + (touch_switch.rect.right + 68, touch_switch.rect.centery - 88), + ), + stylus_switch, + Icon( + self, + stylus, + (stylus_switch.rect.right + 68, stylus_switch.rect.centery - 88), + ), + Button( + self, + pygame.Rect((784, 748), (384, 128)), + "Re-apply", + partial(self.xinput_conf.reapply_by_type, "touchpad") + ), + Button( + self, + pygame.Rect((784, 944), (384, 128)), + "Re-apply", + partial(self.xinput_conf.reapply_by_type, "stylus") + ), ) def handle_event(self, ev): @@ -79,73 +112,25 @@ class ZenbookConf: if ev.key == pygame.K_ESCAPE: self.running = False return False - elif ev.type == pygame.MOUSEBUTTONDOWN: - for item in self.SHAPES: - if item["rect"].collidepoint(ev.pos): - self.xrandr_conf.update(item["name"]) - if item["name"] != "single": - self.bluetooth_conf.update(True) - self.bt_switch.update(True) - settings_per_device_type = { - "touchpad": self.touch_switch.setting, - "stylus": self.stylus_switch.setting, - } - for device_type, setting in settings_per_device_type.items(): - if setting is not None: - self.xinput_conf.update_by_type(device_type, setting) - self.dirty = True - else: - self.bt_switch.handle_mousebuttondown(ev) - self.touch_switch.handle_mousebuttondown(ev) - self.stylus_switch.handle_mousebuttondown(ev) - self.dirty |= self.touch_button.handle_event(ev) - self.dirty |= self.stylus_button.handle_event(ev) + method_name = f"handle_{pygame.event.event_name(ev.type).lower()}" + for child in self.children: + method = getattr(child, method_name, None) + if method is None: + continue + method(ev) return True def update(self): - self.dirty |= self.bt_switch.update() - self.dirty |= self.touch_switch.update() - self.dirty |= self.stylus_switch.update() + for child in self.children: + child.update() if self.clock.get_fps() != self.current_fps: self.current_fps = int(self.clock.get_fps()) self.dirty = True def draw(self): self.surf.fill(0x333333) - for item in self.SHAPES: - if self.xrandr_conf.is_active(item["name"]): - pygame.draw.rect(self.surf, "lime", item["rect"], 8) - else: - pygame.draw.rect(self.surf, "gray", item["rect"], 8) - item["shape"].draw( - self.surf, - (item["rect"].left + 32, item["rect"].top + 32), - (16, 16), - "white", - ) - - self.bt_switch.draw(self.surf) - fs = self.font.render("Bluetooth", True, "gray") - r = self.bt_switch.rect - self.surf.blit(fs, (r.right + 68, r.centery - fs.get_height() // 2)) - - self.touch_switch.draw(self.surf) - touchscreen.draw( - self.surf, - (self.touch_switch.rect.right + 68, self.touch_switch.rect.centery - 88), - (8, 8), - "gray", - ) - self.touch_button.draw(self.surf) - - self.stylus_switch.draw(self.surf) - stylus.draw( - self.surf, - (self.stylus_switch.rect.right + 68, self.stylus_switch.rect.centery - 88), - (8, 8), - "gray", - ) - self.stylus_button.draw(self.surf) + for child in self.children: + child.draw() def run(self): while True: