if self.moving_since is not nan:
self.dirty = True
+ def set_value(self, value):
+ if value == self.value:
+ return
+ self.value = value
+ if value is None:
+ self.moving_since = time() - self.MOVE_FOR_SEC / 2
+ else:
+ self.moving_since = time()
+
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
return
- self.value = bool(self.value) ^ True
- offset = self.MOVE_FOR_SEC / 2 if self.value is None else 0
- self.moving_since = time() - offset
+ self.set_value(bool(self.value) ^ True)
class Cursor(EventMethodDispatcher):
self.focus()
elif self.cursor is not None:
self.blur(True)
+
+
+class FPSWidget(UIChild):
+ FPS_COLOR = "yellow"
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.clock = self.parent.clock
+ self.current_fps = None
+
+ def update(self):
+ new_fps = int(self.clock.get_fps())
+ if self.current_fps != new_fps:
+ self.current_fps = new_fps
+ self.dirty = True
+
+ def draw(self):
+ surf_size = self.surf.get_size()
+ fs = self.font.render(
+ f"{int(self.current_fps)} FPS", True, self.FPS_COLOR
+ )
+ fs_size = fs.get_size()
+ self.surf.blit(
+ fs, (surf_size[0] - fs_size[0] - 7, surf_size[1] - fs_size[1] - 7)
+ )
+
+
+class Icon(UIChild):
+ def __init__(self, parent, shape):
+ super().__init__(parent)
+ self.shape = shape
+
+ def draw(self):
+ self.shape.draw(self.surf, "gray")
+
+
+class IconButton(Button):
+ def __init__(self, parent, shape, *args, **kwargs):
+ super().__init__(parent, *args, **kwargs)
+ self.shape = shape
+
+ def draw(self):
+ if self.pushed:
+ pygame.draw.rect(self.parent.surf, "honeydew4", self.rect)
+ self.shape.draw(self.parent.surf, "black" if self.pushed else "white")
+ if self.is_active:
+ color = "lime"
+ elif self.pushed:
+ color = "red"
+ else:
+ color = "gray"
+ pygame.draw.rect(self.parent.surf, color, self.rect, 8)
--- /dev/null
+from functools import partial
+
+import pygame
+
+from .bluetooth import BluetoothConf
+from ui.ui import Button, FPSWidget, Icon, IconButton, Switch, UIParent
+from .shapes import (
+ bluetooth,
+ laptop_double,
+ laptop_single,
+ laptop_vertical,
+ touchscreen,
+ stylus,
+)
+from .xinput import XinputConf
+from .xrandr import XrandrConf
+
+
+class ZenbookConf(UIParent):
+ BACKGROUND_COLOR = 0x333333
+
+ def __init__(self):
+ pygame.init()
+ pygame.display.set_icon(self.get_icon())
+ pygame.display.set_caption("Zenbook Config")
+ window_size = (1536, 1200)
+ super().__init__(
+ pygame.display.set_mode(window_size, display=0),
+ pygame.font.Font(None, size=96),
+ )
+ self.current_display = 0
+ self.xrandr_conf = XrandrConf()
+ self.xinput_conf = XinputConf(self.xrandr_conf)
+ self.bluetooth_conf = BluetoothConf()
+ bt_switch = Switch(
+ self,
+ pygame.Rect((128, 612), (256, 128)),
+ self.bluetooth_conf.update,
+ self.bluetooth_conf.conf
+ )
+ touch_switch = Switch(
+ self,
+ pygame.Rect((128, 808), (256, 128)),
+ partial(self.xinput_conf.update_by_type, "touchpad"),
+ self.xinput_conf.conf_by_type("touchpad"),
+ )
+ stylus_switch = Switch(
+ self,
+ pygame.Rect((128, 1004), (256, 128)),
+ partial(self.xinput_conf.update_by_type, "stylus"),
+ self.xinput_conf.conf_by_type("stylus"),
+ )
+ top = 128
+ self.single_button = IconButton(
+ self,
+ laptop_single.fit((100, top + 32), (16, 16)),
+ pygame.Rect((68, top), (416, 416)),
+ None,
+ partial(
+ self.laptop_cb, "single", bt_switch, touch_switch, stylus_switch
+ ),
+ self.xrandr_conf.is_active("single"),
+ )
+ self.double_button = IconButton(
+ self,
+ laptop_double.fit((600, top + 32), (16, 16)),
+ pygame.Rect((568, top), (416, 416)),
+ None,
+ partial(
+ self.laptop_cb, "double", bt_switch, touch_switch, stylus_switch
+ ),
+ self.xrandr_conf.is_active("double"),
+ )
+ self.vertical_button = IconButton(
+ self,
+ laptop_vertical.fit((1100, top + 32), (16, 16)),
+ pygame.Rect((1068, top), (416, 416)),
+ None,
+ partial(
+ self.laptop_cb,
+ "vertical",
+ bt_switch,
+ touch_switch,
+ stylus_switch,
+ ),
+ self.xrandr_conf.is_active("vertical"),
+ )
+ self.children.extend(
+ (
+ FPSWidget(self),
+ self.single_button,
+ self.double_button,
+ self.vertical_button,
+ bt_switch,
+ Icon(
+ self,
+ bluetooth.fit(
+ (bt_switch.rect.right + 68, bt_switch.rect.centery - 88),
+ (8, 8),
+ ),
+ ),
+ touch_switch,
+ Icon(
+ self,
+ touchscreen.fit(
+ (touch_switch.rect.right + 68, touch_switch.rect.centery - 88),
+ (8, 8),
+ ),
+ ),
+ stylus_switch,
+ Icon(
+ self,
+ stylus.fit(
+ (
+ stylus_switch.rect.right + 68,
+ stylus_switch.rect.centery - 88,
+ ),
+ (8, 8),
+ ),
+ ),
+ Button(
+ self,
+ pygame.Rect((784, touch_switch.rect.top), (384, 128)),
+ "Re-apply",
+ partial(self.xinput_conf.reapply_by_type, "touchpad")
+ ),
+ Button(
+ self,
+ pygame.Rect((784, stylus_switch.rect.top), (384, 128)),
+ "Re-apply",
+ partial(self.xinput_conf.reapply_by_type, "stylus")
+ ),
+ Button(
+ self,
+ pygame.Rect((window_size[0] - 128, 0), (128, 96)),
+ "×",
+ self.quit,
+ ),
+ Button(
+ self,
+ pygame.Rect((window_size[0] - 256, 0), (128, 96)),
+ "_",
+ self.iconify,
+ ),
+ Button(
+ self,
+ pygame.Rect((window_size[0] - 384, 0), (128, 96)),
+ "»",
+ self.next_display,
+ ),
+ )
+ )
+
+ def get_icon(self):
+ surf = pygame.Surface((512, 512), pygame.SRCALPHA, 32)
+ surf.fill(0x0)
+ v = 512 // 22
+ laptop_single.fit((0, 0), (v, v)).draw(surf, "white")
+ return pygame.transform.scale(surf, (32, 32))
+
+ def laptop_cb(self, name, bt_switch, touch_switch, stylus_switch):
+ self.xrandr_conf.update(name)
+ if name != "single":
+ self.bluetooth_conf.update(True)
+ bt_switch.set_value(True)
+ settings_per_device_type = {
+ "touchpad": touch_switch.value,
+ "stylus": stylus_switch.value,
+ }
+ for device_type, value in settings_per_device_type.items():
+ if value is not None:
+ self.xinput_conf.update_by_type(device_type, value)
+ self.single_button.is_active = self.xrandr_conf.is_active("single")
+ self.double_button.is_active = self.xrandr_conf.is_active("double")
+ self.vertical_button.is_active = self.xrandr_conf.is_active("vertical")
+ self.dirty = True
+
+ def quit(self):
+ self.running = False
+
+ def iconify(self):
+ pygame.display.iconify()
+
+ def next_display(self):
+ current_display = (self.current_display + 1) % self.xrandr_conf.count_active()
+ if current_display != self.current_display:
+ self.current_display = current_display
+ self.surf = pygame.display.set_mode(
+ self.surf.get_size(), display=self.current_display
+ )
+ self.dirty = True