git.lucas.co / hou-control
git clone https://git.lucas.co/hou-control.git

python3.11libs/hc/hcwindowwatcher.py (2.9K)

 1 import hou
 2 from PySide6.QtCore import QEvent, QObject
 3 
 4 
 5 class HCWindowWatcher(QObject):
 6     EVENT_MAP = {
 7         QEvent.Enter:            "enter",
 8         QEvent.Leave:            "leave",
 9         QEvent.WindowActivate:   "focus",
10         QEvent.WindowDeactivate: "unfocus",
11     }
12 
13     def __init__(self):
14         super().__init__(hou.qt.mainWindow())
15         self._installed = False
16         self._watched = []
17         self._in_window = False
18         self._counts = {name: 0 for name in self.EVENT_MAP.values()}
19         self._callbacks = {name: [] for name in self.EVENT_MAP.values()}
20 
21     def _targets(self):
22         from PySide6.QtWidgets import QWidget
23         main = hou.qt.mainWindow()
24         targets = [main]
25         gl = main.findChild(QWidget, "RE_GLDrawableWrapper")
26         if gl is not None:
27             targets.append(gl)
28         return targets
29 
30     def start(self):
31         if self._installed:
32             return
33         self._watched = self._targets()
34         for t in self._watched:
35             t.installEventFilter(self)
36         self._installed = True
37 
38     def stop(self):
39         if not self._installed:
40             return
41         for t in self._watched:
42             t.removeEventFilter(self)
43         self._watched = []
44         self._installed = False
45 
46     def toggle(self):
47         if self._installed:
48             self.stop()
49         else:
50             self.start()
51 
52     def isRunning(self):
53         return self._installed
54 
55     def counts(self):
56         return dict(self._counts)
57 
58     def on(self, name, callback):
59         if name not in self._callbacks:
60             raise ValueError(f"unknown event: {name}")
61         if callback not in self._callbacks[name]:
62             self._callbacks[name].append(callback)
63 
64     def off(self, name, callback):
65         if name in self._callbacks and callback in self._callbacks[name]:
66             self._callbacks[name].remove(callback)
67 
68     def _fire(self, name):
69         for cb in self._callbacks[name]:
70             try:
71                 cb()
72             except Exception as e:
73                 print(f"[HCWindowWatcher] {name} callback error: {e!r}")
74 
75     def _cursorInsideMain(self):
76         main = hou.qt.mainWindow()
77         pos = main.mapFromGlobal(main.cursor().pos())
78         return main.rect().contains(pos)
79 
80     def eventFilter(self, obj, event):
81         et = event.type()
82         if et == QEvent.Enter:
83             if not self._in_window:
84                 self._in_window = True
85                 self._counts["enter"] += 1
86                 self._fire("enter")
87         elif et == QEvent.Leave:
88             if self._in_window and not self._cursorInsideMain():
89                 self._in_window = False
90                 self._counts["leave"] += 1
91                 self._fire("leave")
92         elif et == QEvent.WindowActivate:
93             self._counts["focus"] += 1
94             self._fire("focus")
95         elif et == QEvent.WindowDeactivate:
96             self._counts["unfocus"] += 1
97             self._fire("unfocus")
98         return False