diff --git a/daemon.py b/daemon.py index 6f56727..5f5373b 100755 --- a/daemon.py +++ b/daemon.py @@ -4,15 +4,15 @@ import modules import modules.core from modules.audiooutput import PulseCtlDefaultSinkCycleAction from modules.audiooutput import naming_map, sink_filter, sink_input_filter -from modules.cycle import * +from modules.cycle import CycleControl from modules.toggle import CommandToggleControl -from modules.screenlayout import ScreenLayoutCycleAction +from modules.functional import * logging.basicConfig(level=logging.DEBUG) logging.getLogger('modules.core').setLevel(logging.WARNING) modules.Application( - CycleControl(ScreenLayoutCycleAction()), + CycleControl(modules.ScreenLayoutCycleAction(name=partial(drop_from, '.')), scroll_actions=False), modules.GroupedControl( modules.CaffeineControl(), modules.RedshiftControl(), @@ -21,14 +21,14 @@ modules.Application( modules.GroupedControl( CycleControl( PulseCtlDefaultSinkCycleAction( - naming_map=naming_map.partial( - naming_map.foldr, [ + naming_map=partial( + foldr, [ naming_map.description, - naming_map.partial( - naming_map.drop_kwargs, - naming_map.partial(naming_map.foldr, [ - naming_map.partial(naming_map.drop_first_if_eq, 'Built-in Audio '), - naming_map.first_char + partial( + drop_kwargs, + partial(foldr, [ + partial(drop_first_if_eq, 'Built-in Audio '), + first_char ]) ) ] diff --git a/modules/__init__.py b/modules/__init__.py index 97ec9a1..e0e4bb0 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -3,3 +3,4 @@ from .core import GroupedControl, ActionWrapperControl from .caffeine import CaffeineControl from .redshift import RedshiftControl from .volume import VolumeControl +from .screenlayout import ScreenLayoutCycleAction diff --git a/modules/audiooutput/naming_map.py b/modules/audiooutput/naming_map.py index 37ea90f..8814710 100644 --- a/modules/audiooutput/naming_map.py +++ b/modules/audiooutput/naming_map.py @@ -1,5 +1,5 @@ import pulsectl -from functools import partial, reduce +from ..functional import * def description(sink: pulsectl.PulseSinkInfo, **k) -> str: @@ -8,58 +8,3 @@ def description(sink: pulsectl.PulseSinkInfo, **k) -> str: """ return sink.description - -def n_chars(n: int, s) -> str: - """ - Takes the first n characters - """ - return s[0:n] - - -first_char = partial(n_chars, 1) - - -def first_word(s: str) -> str: - """ - Takes the first word - """ - return s.split(' ')[0] - - -def drop_first_n_words(n: int, s: str) -> str: - """ - Removes the first word - """ - return ' '.join(s.split(' ')[n:]) - - -drop_first_word = partial(drop_first_n_words, 1) - - -def drop_first_word_if_eq(drop_if: str, s: str) -> str: - return drop_first_word(s) if drop_if == first_word(s) else s - - -def apply(*args: [callable], **k): - fns = args[:-1] - data = args[-1] - for fn in fns: - data = fn(data, **k) - k = {} - return data - - -def drop_first_if_eq(drop_if: str, s: str) -> str: - return s[len(drop_if):] if s[0:len(drop_if)] == drop_if else s - - -def apply(x, y, **k): - return y(x, **k) - - -def foldr(fns, data, **kwargs): - return reduce(partial(apply, **kwargs), fns, data) - - -def drop_kwargs(x, *a, **k): - return x(*a) diff --git a/modules/cycle.py b/modules/cycle.py index 8909a4c..470e8ae 100644 --- a/modules/cycle.py +++ b/modules/cycle.py @@ -109,8 +109,9 @@ class CycleControl(WrappingControl): When clicked or scrolled over it changes to the previous/next value in a circular fashion. """ - def __init__(self, cycle_action: AbstractCycleAction): + def __init__(self, cycle_action: AbstractCycleAction, scroll_actions=True): super().__init__(cycle_action) + self.__scroll_actions = scroll_actions def respond_to(self, command: str): if command == ':next': @@ -121,12 +122,17 @@ class CycleControl(WrappingControl): return True def __str__(self): + next_button = Button.LEFT + prev_button = Button.RIGHT + if self.__scroll_actions: + next_button |= Button.SCROLL_UP + prev_button |= Button.SCROLL_DOWN return action( command=self.create_pipe_command(':next'), - button=Button.LEFT | Button.SCROLL_UP, + button=next_button, text=action( command=self.create_pipe_command(':prev'), - button=Button.RIGHT | Button.SCROLL_DOWN, + button=prev_button, text=str(self.child) ) ) diff --git a/modules/functional.py b/modules/functional.py new file mode 100644 index 0000000..7d24dc1 --- /dev/null +++ b/modules/functional.py @@ -0,0 +1,63 @@ +from functools import partial, reduce + +def n_chars(n: int, s) -> str: + """ + Takes the first n characters + """ + return s[0:n] + + +first_char = partial(n_chars, 1) + + +def first_word(s: str) -> str: + """ + Takes the first word + """ + return s.split(' ')[0] + + +def drop_first_n_words(n: int, s: str) -> str: + """ + Removes the first word + """ + return ' '.join(s.split(' ')[n:]) + + +drop_first_word = partial(drop_first_n_words, 1) + + +def drop_first_word_if_eq(drop_if: str, s: str) -> str: + return drop_first_word(s) if drop_if == first_word(s) else s + + +def apply(*args: [callable], **k): + fns = args[:-1] + data = args[-1] + for fn in fns: + data = fn(data, **k) + k = {} + return data + + +def drop_first_if_eq(drop_if: str, s: str) -> str: + return s[len(drop_if):] if s[0:len(drop_if)] == drop_if else s + +def drop_until(until: str, s: str) -> str: + return s[s.find(until):] + +def drop_from(end: str, s: str) -> str: + idx = s.find(end) + return s[:idx] if idx >= 0 else s + + +def apply(x, y, **k): + return y(x, **k) + + +def foldr(fns, data, **kwargs): + return reduce(partial(apply, **kwargs), fns, data) + + +def drop_kwargs(x, *a, **k): + return x(*a) diff --git a/modules/screenlayout.py b/modules/screenlayout.py index f14167e..5d57046 100644 --- a/modules/screenlayout.py +++ b/modules/screenlayout.py @@ -9,10 +9,11 @@ import argparse logger = logging.getLogger(__name__) class ScreenLayoutCycleAction(OrderedDictCycleAction): - def __init__(self): + def __init__(self, name: callable): self.__od = OrderedDict() super().__init__(self.__od) self.__inhibited = True + self.__naming_func = name def configure(self, argument_parser: argparse.ArgumentParser): argument_parser.add_argument('--screenlayout-dir', help='Directory containing screenlayout shell files.', type=str) @@ -40,6 +41,9 @@ class ScreenLayoutCycleAction(OrderedDictCycleAction): return True return False + def __str__(self): + return self.__naming_func(super().__str__()) + def __load_layouts(self, directory): entries = os.scandir(directory) for entry in entries: