#!/usr/bin/env python3 import enum import logging import threading import time # TODO Update strategies (periodic, inotify file) # TODO Section order (priority system maybe ?) # TODO Allow deletion of Bar, BarGroup and Section for screen changes # TODO Optimize to use write() calls instead of string concatenation (writing # BarGroup strings should be a good compromise) class BarGroupType(enum.Enum): LEFT = 0 RIGHT = 1 # MID_LEFT = 2 # MID_RIGHT = 3 class Bar: """ One bar for each screen """ everyone = set() string = "" @staticmethod def init(): Section.init() # Debug Bar() def __init__(self): self.screen = 0 # TODO self.groups = dict() for groupType in BarGroupType: group = BarGroup(groupType, self) self.groups[groupType] = group self.childsChanged = False self.everyone.add(self) @staticmethod def addSectionAll(section, group, screens=None): """ .. note:: Add the section before updating it for the first time. """ assert isinstance(section, Section) assert isinstance(group, BarGroupType) # TODO screens selection for bar in Bar.everyone: bar.addSection(section, group=group) def addSection(self, section, group): assert isinstance(section, Section) assert isinstance(group, BarGroupType) self.groups[group].addSection(section) def update(self): if self.childsChanged: self.string = "" self.childsChanged = False @staticmethod def updateAll(): for bar in Bar.everyone: bar.update() Bar.string = "" class BarGroup: """ One for each group of each bar """ everyone = set() def __init__(self, groupType, parent): assert isinstance(groupType, BarGroupType) assert isinstance(parent, Bar) self.groupType = groupType self.parent = parent self.sections = list() self.string = '' self.form = '' #: One of the sections that had their theme or visibility changed self.childsThemeChanged = False #: One of the sections that had their text (maybe their size) changed self.childsTextChanged = False BarGroup.everyone.add(self) def addSection(self, section): self.sections.append(section) section.parents.add(self) def update(self): if self.childsThemeChanged: # TODO self.form = ">".join([sec.curText for sec in self.sections if sec.visible]) if self.childsTextChanged or self.childsThemeChanged: print("118") self.string = ">".join([sec.curText for sec in self.sections if sec.visible]) print("|{0}|".format(self.string)) self.parent.childsChanged = True self.childsThemeChanged = False self.childsTextChanged = False @staticmethod def updateAll(): print("130") for group in BarGroup.everyone: group.update() Bar.updateAll() class SectionThread(threading.Thread): def run(self): while Section.somethingChanged.wait(): Section.updateAll() while len(Section.sizeChanging) > 0: time.sleep(0.1) Section.updateAll() class Section: #: Sections that do not have their destination size sizeChanging = set() somethingChanged = threading.Event() updateThread = None @staticmethod def init(): Section.updateThread = SectionThread(daemon=True) Section.updateThread.start() def __init__(self): #: Displayed section #: Note: A section can be empty and displayed! self.visible = False #: Displayed text self.curText = '' #: Displayed text size self.curSize = 0 #: Destination text self.dstText = '' #: Destination size self.dstSize = 0 #: Groups that have this section self.parents = set() def informParentsThemeChanged(self): for parent in self.parents: parent.childsThemeChanged = True def informParentsTextChanged(self): for parent in self.parents: parent.childsTextChanged = True def updateText(self, text): if len(text): self.dstText = ' {} '.format(text) self.dstSize = len(self.dstText) else: self.dstSize = 0 if self.curSize == self.dstSize: self.curText = self.dstText self.informParentsTextChanged() else: Section.sizeChanging.add(self) Section.somethingChanged.set() def updateVisibility(self, visibility): assert isinstance(visibility, bool) self.visible = visibility self.informParentsThemeChanged() Section.somethingChanged.set() @staticmethod def fit(text, size): t = len(text) return text[:size] if t >= size else text + " " * (size - t) def update(self): # TODO Might profit of a better logic if not self.visible: self.updateVisibility(True) return if self.dstSize > self.curSize: self.curSize += 1 elif self.dstSize < self.curSize: self.curSize -= 1 else: # Visibility toggling must be done one step after curSize = 0 if self.dstSize == 0: self.updateVisibility(False) Section.sizeChanging.remove(self) return self.curText = Section.fit(self.dstText, self.curSize) self.informParentsTextChanged() @staticmethod def updateAll(): """ Process all sections for text size changes """ for sizeChanging in Section.sizeChanging.copy(): sizeChanging.update() # print("{1:3d} |{0}|".format(sizeChanging.curText, sizeChanging.curSize)) BarGroup.updateAll() Section.somethingChanged.clear() if __name__ == '__main__': Bar.init() sec = Section() sec1 = Section() Bar.addSectionAll(sec, BarGroupType.LEFT) Bar.addSectionAll(sec1, BarGroupType.LEFT) sec.updateText("Hello") # sec1.updateText("world!") time.sleep(2) sec.updateText("Salut") # sec1.updateText("le monde !") time.sleep(2) sec.updateText("") # sec1.updateText("") time.sleep(2)