214 lines
4.3 KiB
Python
214 lines
4.3 KiB
Python
from .functions import (
|
|
connect,
|
|
set_image
|
|
)
|
|
|
|
|
|
class PropertyBase:
|
|
_app = None
|
|
_db = None
|
|
_window = None
|
|
|
|
@property
|
|
def app(self):
|
|
return self._app or Gio.Application.get_default()
|
|
|
|
|
|
@app.setter
|
|
def app(self, value):
|
|
self._app = value
|
|
|
|
|
|
@property
|
|
def db(self):
|
|
return self._db or self.app.db
|
|
|
|
|
|
@db.setter
|
|
def db(self, value):
|
|
self._db = value
|
|
|
|
|
|
@property
|
|
def window(self):
|
|
return self._window or self.app.window
|
|
|
|
|
|
@window.setter
|
|
def window(self, value):
|
|
self._window = value
|
|
|
|
|
|
class BuilderBase(PropertyBase):
|
|
def __init__(self, path):
|
|
self._path = path
|
|
self._builder = Gtk.Builder.new_from_file(path)
|
|
self._connected_sigs = {}
|
|
|
|
|
|
def __getitem__(self, name):
|
|
if not (widget := self._builder.get_object(name)):
|
|
raise KeyError(f'Widget with ID "{name}" does not exist.')
|
|
|
|
return widget
|
|
|
|
|
|
def __setitem__(self, name, widget):
|
|
try:
|
|
self[name]
|
|
raise KeyError(f'Widget ID already exists: {name}')
|
|
|
|
except KeyError:
|
|
self._builder.expose_object(name, widget)
|
|
|
|
return widget
|
|
|
|
|
|
def __delitem__(self, name):
|
|
self[name].destroy()
|
|
|
|
|
|
def __del__(self):
|
|
self.destroy()
|
|
|
|
|
|
@property
|
|
def path(self):
|
|
return self._path
|
|
|
|
|
|
def block_signals(self, *names):
|
|
signals = {name: self.get_signals(name) for name in names}
|
|
|
|
return SignalBlock(self, signals)
|
|
|
|
|
|
def connect(self, name, signal, callback, *args, **kwargs):
|
|
widget = self[name]
|
|
|
|
if not self._connected_sigs.get(name):
|
|
self._connected_sigs[name] = {}
|
|
|
|
if signal in self._connected_sigs[name]:
|
|
raise KeyError(f'Signal for "{name}" already connected: {signal}')
|
|
|
|
self._connected_sigs[name][signal] = connect(widget, signal, callback, *args, **kwargs)
|
|
return self._connected_sigs[name][signal]
|
|
|
|
|
|
def disconnect(self, name, signal):
|
|
try:
|
|
sigid = self._connected_sigs[name].pop(signal)
|
|
self[name].disconnect(sigid)
|
|
|
|
except KeyError:
|
|
raise KeyError(f'Signal for "{name}" not connected: {signal}')
|
|
|
|
|
|
def destroy(self):
|
|
for widget in self._builder.get_objects():
|
|
try: widget.destroy()
|
|
except: pass
|
|
|
|
self._connected_sigs = {}
|
|
|
|
|
|
def get_signals(self, name):
|
|
return self._connected_sigs[name]
|
|
|
|
|
|
def reload(self):
|
|
self.destroy(False)
|
|
self._builder.add_from_file(self.path)
|
|
|
|
|
|
def set_icon(self, name, obj, size=16, keep='width'):
|
|
set_image(self[name], obj, size, keep)
|
|
|
|
|
|
def set_icon_from_resource(self, name, filename, size=16, keep='width'):
|
|
path = self.app.path.resources.join('icons').join(f'{filename}')
|
|
self.set_icon(name, path, size, keep)
|
|
|
|
|
|
class ComponentBase(PropertyBase):
|
|
signals = {}
|
|
|
|
def __init__(self, prefix=None):
|
|
self._prefix = prefix
|
|
|
|
|
|
def __getitem__(self, key):
|
|
key = f'{self._prefix}-{key}' if self._prefix else key
|
|
return self.window[key]
|
|
|
|
|
|
def __setitem__(self, key, widget):
|
|
key = f'{self._prefix}-{key}' if self._prefix else key
|
|
self.window[key] = widget
|
|
|
|
|
|
def __delitem__(self, key):
|
|
key = f'{self._prefix}-{key}' if self._prefix else key
|
|
del self.window[key]
|
|
|
|
|
|
def block_signals(self, *names):
|
|
return BuilderBase.block_signals(self, *names)
|
|
|
|
|
|
def connect(self, name, signal, callback, *args, **kwargs):
|
|
name = f'{self._prefix}-{name}' if self._prefix else name
|
|
return self.window.connect(name, signal, callback, *args, **kwargs)
|
|
|
|
|
|
def disconnect(self, name, signal):
|
|
name = f'{self._prefix}-{name}' if self._prefix else name
|
|
return self.window.disconnect(name, signal)
|
|
|
|
|
|
def get_signals(self, name):
|
|
return self._window._connected_sigs[f'{self._prefix}-{name}']
|
|
|
|
|
|
def set_icon(self, name, obj, size=16):
|
|
BuilderBase.set_icon(self, name, obj, size)
|
|
|
|
|
|
def set_icon_from_resource(self, name, filename, size=16):
|
|
Builder.set_icon_from_resource(self, name, filename, size)
|
|
|
|
|
|
def setup_signals(self):
|
|
for name, sigs in self.signals.items():
|
|
for data in sigs:
|
|
data = DotDict(data)
|
|
if name.startswith('menu'):
|
|
data.args.append('menu')
|
|
|
|
self.connect(name, data.signal, data.callback, *data.get('args', []), **data.get('kwargs', {}))
|
|
|
|
|
|
class SignalBlock:
|
|
def __init__(self, parent, signals):
|
|
self.parent = parent
|
|
self.signals = signals
|
|
|
|
|
|
def __enter__(self):
|
|
self.set_block(True)
|
|
|
|
|
|
def __exit__(self, *args):
|
|
self.set_block(False)
|
|
|
|
|
|
def set_block(self, block):
|
|
for name, signals in self.signals.items():
|
|
for signame, sigid in signals.items():
|
|
if block:
|
|
self.parent[name].handler_block(sigid)
|
|
|
|
else:
|
|
self.parent[name].handler_unblock(sigid)
|