"""Main container of the tagit UI. Part of the tagit module. A copy of the license is provided with the project. Author: Matthias Baumgartner, 2022 """ # standard imports import logging import os import typing # kivy imports from kivy.clock import Clock from kivy.lang import Builder from kivy.uix.floatlayout import FloatLayout import kivy.properties as kp # import Image and Loader to overwrite their caches later on from kivy.cache import Cache from kivy.loader import Loader from kivy.resources import resource_find # tagit imports from tagit import actions, config, dialogues from tagit.widgets.browser import Browser from tagit.widgets.context import Context from tagit.widgets.dock import TileDock, ButtonDock, KeybindDock from tagit.widgets.filter import Filter from tagit.widgets.keyboard import Keyboard from tagit.widgets.session import Session from tagit.widgets.status import Status # exports __all__: typing.Sequence[str] = ( 'KIVY_IMAGE_CACHE_SIZE', 'KIVY_IMAGE_CACHE_TIMEOUT', 'MainWindow', ) ## code ## logger = logging.getLogger(__name__) # load kv Builder.load_file(os.path.join(os.path.dirname(__file__), 'desktop.kv')) # load styles Builder.load_file(resource_find('default/style.kv')) # classes class MainWindow(FloatLayout): """A self-contained user interface for desktop usage. See `tagit.apps.gui` for an example of how to invoke it. """ keys = kp.ObjectProperty(None) # unnecessary but nicely explicit browser = kp.ObjectProperty(None) filter = kp.ObjectProperty(None) keytriggers = kp.ObjectProperty(None) # FIXME: log actions and and replay them action_log = kp.ListProperty() def __init__ (self, cfg, stor, log, **kwargs): # initialize the session self._session = Session(cfg, stor, log) # initialize key-only actions self.keys = Keyboard() # initialize the cache cache_size = max(0, cfg('ui', 'standalone', 'browser', 'cache_size')) cache_size = cache_size if cache_size > 0 else None cache_timeout = max(0, cfg('ui', 'standalone', 'browser', 'cache_timeout')) cache_timeout = cache_timeout if cache_timeout > 0 else None Cache.register('kv.loader', limit=cache_size, timeout=cache_timeout) # initialize the widget super(MainWindow, self).__init__(**kwargs) # bind pre-close checks from kivy.core.window import Window Window.bind(on_request_close=self.on_request_close) Window.size = tuple(cfg('ui', 'standalone', 'window_size')) if cfg('ui', 'standalone', 'maximize'): Window.maximize() ## properties @property def session(self): return self._session def trigger(self, action, *args, **kwargs): """Trigger an action once.""" actions.ActionBuilder().get(action).single_shot(self, *args, **kwargs) ## startup and shutdown def on_startup(self): # run script for args in self.session.cfg('session', 'script'): if isinstance(args, str): cmd, args = args, [] else: cmd = args.pop(0) Clock.schedule_once( lambda dt, cmd=cmd, args=args: self.trigger(cmd, *args), self.session.cfg('session', 'script_delay')) # FIXME: mb/port: debugging only #return #Clock.schedule_once(lambda dt: self.trigger('Search'), 0) #Clock.schedule_once(lambda dt: self.trigger('ZoomOut'), 0) #Clock.schedule_once(lambda dt: self.trigger('ZoomOut'), 0) #from kivy.app import App #App.get_running_app().stop() def on_request_close(self, *args): #with open('.action_history', 'a') as ofile: # for itm in self.action_log: # ofile.write(f'{itm}\n') #App.get_running_app().stop() # FIXME: mb/port: from CloseSessionAndExit return False ## config ## config.declare(('session', 'script'), config.List(config.Any()), [], __name__, 'start script', 'Actions to run after startup. Intended for testing.') config.declare(('session', 'script_delay'), config.Unsigned(), 0, __name__, 'script delay', 'Start script execution delay in seconds.') config.declare(('ui', 'standalone', 'maximize'), config.Bool(), False, __name__, 'Window maximization', 'Maximize the window upon startup.') config.declare(('ui', 'standalone', 'window_size'), config.List(config.Unsigned()), (1024, 768), __name__, 'Wndow size', 'Set the window size upon startup.') config.declare(('ui', 'standalone', 'browser', 'cache_size'), config.Unsigned(), 1000, __name__, 'Cache size', 'Number of preview images that are held in the cache. Should be high or zero if memory is not an issue. Set to a small value to preserve memory, but should be at least the most common page size. It is advised to set a value in accordance with `ui.standalone.browser.cache_items`. If zero, no limit applies.') config.declare(('ui', 'standalone', 'browser', 'cache_timeout'), config.Unsigned(), 0, __name__, 'Cache timeout', 'Number of seconds until cached items are discarded. Should be high or zero if memory is not an issue. Set it to a small value to preserve memory when browsing through many images. If zero, no limit applies. Specify in seconds.') ## EOF ##