More bar things
This commit is contained in:
parent
ca9d5e279e
commit
d010c48306
|
@ -12,9 +12,14 @@ if __name__ == "__main__":
|
|||
WORKSPACE_THEME = 0
|
||||
FOCUS_THEME = 3
|
||||
URGENT_THEME = 1
|
||||
CUSTOM_SUFFIXES = '▲■'
|
||||
|
||||
Bar.addSectionAll(I3WorkspacesProvider(theme=WORKSPACE_THEME, themeFocus=FOCUS_THEME, themeUrgent=URGENT_THEME, themeMode=URGENT_THEME), BarGroupType.LEFT)
|
||||
|
||||
customNames = dict()
|
||||
for i in range(len(CUSTOM_SUFFIXES)):
|
||||
short = str(i+1)
|
||||
full = short + ' ' + CUSTOM_SUFFIXES[i]
|
||||
customNames[short] = full
|
||||
Bar.addSectionAll(I3WorkspacesProvider(theme=WORKSPACE_THEME, themeFocus=FOCUS_THEME, themeUrgent=URGENT_THEME, themeMode=URGENT_THEME, customNames=customNames), BarGroupType.LEFT)
|
||||
|
||||
# TODO Middle
|
||||
Bar.addSectionAll(MpdProvider(theme=7), BarGroupType.LEFT)
|
||||
|
|
|
@ -54,7 +54,7 @@ class Bar:
|
|||
def init():
|
||||
Section.init()
|
||||
|
||||
cmd = ['lemonbar', '-b']
|
||||
cmd = ['lemonbar', '-b', '-a', '64']
|
||||
for font in Bar.FONTS:
|
||||
cmd += ["-f", "{}:size={}".format(font, Bar.FONTSIZE)]
|
||||
Bar.process = subprocess.Popen(cmd, stdin=subprocess.PIPE,
|
||||
|
@ -326,6 +326,7 @@ class Section:
|
|||
self.parents = set()
|
||||
|
||||
self.icon = self.ICON
|
||||
self.persistent = self.PERSISTENT
|
||||
|
||||
|
||||
def __str__(self):
|
||||
|
@ -354,19 +355,15 @@ class Section:
|
|||
parent.childsTextChanged = True
|
||||
|
||||
def updateText(self, text):
|
||||
assert not isinstance(text, list) # Old behaviour, keep it until everything is cleaned
|
||||
if isinstance(text, str):
|
||||
text = Text(text)
|
||||
|
||||
if self.icon:
|
||||
self.dstText[0] = ' ' + self.icon + ' '
|
||||
|
||||
if text is None:
|
||||
self.dstSize = 3 if self.PERSISTENT else 0
|
||||
else:
|
||||
self.dstText[0] = None if (text is None and not self.persistent) else ((' ' + self.icon + ' ') if self.icon else ' ')
|
||||
self.dstText[1] = text
|
||||
self.dstText.setSection(self)
|
||||
self.dstText[2] = ' ' if self.dstText[1] is not None and len(self.dstText[1]) else None
|
||||
|
||||
self.dstSize = len(self.dstText)
|
||||
self.dstText.setSection(self)
|
||||
|
||||
if self.curSize == self.dstSize:
|
||||
if self.dstSize > 0:
|
||||
|
@ -441,7 +438,7 @@ class Section:
|
|||
|
||||
|
||||
class StatefulSection(Section):
|
||||
# TODO Allow to temporary expand the section (e.g. when important change)
|
||||
# TODO FEAT Allow to temporary expand the section (e.g. when important change)
|
||||
NUMBER_STATES = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -449,8 +446,8 @@ class StatefulSection(Section):
|
|||
self.state = 0
|
||||
if hasattr(self, 'onChangeState'):
|
||||
self.onChangeState(self.state)
|
||||
self.dstText.setDecorators(scrollUp=self.incrementState,
|
||||
scrollDown=self.decrementState)
|
||||
self.dstText.setDecorators(clickLeft=self.incrementState,
|
||||
clickRight=self.decrementState)
|
||||
|
||||
def incrementState(self):
|
||||
newState = min(self.state + 1, self.NUMBER_STATES - 1)
|
||||
|
@ -617,13 +614,27 @@ class Text:
|
|||
return string
|
||||
|
||||
def __str__(self):
|
||||
# TODO OPTI
|
||||
return self.text()
|
||||
self._genFixs()
|
||||
curString = self.prefix
|
||||
for element in self.elements:
|
||||
if element is None:
|
||||
continue
|
||||
else:
|
||||
curString += str(element)
|
||||
curString += self.suffix
|
||||
return curString
|
||||
|
||||
def __len__(self):
|
||||
# TODO OPTI
|
||||
string, size = self._text()
|
||||
return size
|
||||
curSize = 0
|
||||
for element in self.elements:
|
||||
if element is None:
|
||||
continue
|
||||
elif isinstance(element, Text):
|
||||
curSize += len(element)
|
||||
else:
|
||||
curSize += len(str(element))
|
||||
return curSize
|
||||
|
||||
|
||||
def __getitem__(self, index):
|
||||
return self.elements[index]
|
||||
|
|
|
@ -99,94 +99,96 @@ class CpuProvider(AlertingSection, PeriodicUpdater):
|
|||
elif self.state >= 1:
|
||||
return Section.ramp(percent/100)
|
||||
|
||||
def __init__(self, theme=None, themeDanger=None, themeCritical=None):
|
||||
def __init__(self, theme=None):
|
||||
AlertingSection.__init__(self, theme)
|
||||
PeriodicUpdater.__init__(self)
|
||||
self.changeInterval(1)
|
||||
|
||||
|
||||
class RamProvider(Section, PeriodicUpdater):
|
||||
# TODO Use AlertingSection
|
||||
class RamProvider(AlertingSection, PeriodicUpdater):
|
||||
"""
|
||||
Shows free RAM
|
||||
"""
|
||||
NUMBER_STATES = 4
|
||||
ICON = ''
|
||||
|
||||
def fetcher(self):
|
||||
mem = psutil.virtual_memory()
|
||||
ramp = Section.ramp(1-mem.percent/100)
|
||||
free = humanSize(mem.available)
|
||||
theme = self.themeCritical if mem.percent >= 90 else \
|
||||
(self.themeDanger if mem.percent >= 75 else self.themeNormal)
|
||||
self.updateTheme(theme)
|
||||
return ' {}{}'.format(ramp, free)
|
||||
freePerc = 1-mem.percent/100
|
||||
self.updateLevel(freePerc)
|
||||
|
||||
def __init__(self, theme=None, themeDanger=None, themeCritical=None):
|
||||
if self.state < 1:
|
||||
return None
|
||||
|
||||
text = Text(Section.ramp(freePerc))
|
||||
if self.state >= 2:
|
||||
freeStr = humanSize(mem.available)
|
||||
text.append(freeStr)
|
||||
if self.state >= 3:
|
||||
totalStr = humanSize(mem.total)
|
||||
text.append('/', totalStr)
|
||||
|
||||
return text
|
||||
|
||||
def __init__(self, theme=None):
|
||||
AlertingSection.__init__(self, theme)
|
||||
PeriodicUpdater.__init__(self)
|
||||
Section.__init__(self, theme)
|
||||
self.themeNormal = theme or self.theme
|
||||
self.themeDanger = themeDanger or self.theme
|
||||
self.themeCritical = themeCritical or self.theme
|
||||
self.changeInterval(1)
|
||||
|
||||
class TemperatureProvider(Section, PeriodicUpdater):
|
||||
# TODO Use AlertingSection
|
||||
|
||||
class TemperatureProvider(AlertingSection, PeriodicUpdater):
|
||||
NUMBER_STATES = 2
|
||||
RAMP = ""
|
||||
|
||||
def fetcher(self):
|
||||
allTemp = psutil.sensors_temperatures()
|
||||
|
||||
if 'coretemp' not in allTemp:
|
||||
# TODO Opti Remove interval
|
||||
return ''
|
||||
|
||||
temp = allTemp['coretemp'][0]
|
||||
|
||||
theme = self.themeCritical if temp.current >= temp.critical else \
|
||||
(self.themeDanger if temp.current >= temp.high
|
||||
else self.themeNormal)
|
||||
self.updateTheme(theme)
|
||||
self.warningThresold = temp.high
|
||||
self.dangerThresold = temp.critical
|
||||
self.updateLevel(temp.current)
|
||||
|
||||
ramp = Section.ramp(temp.current/temp.high, self.RAMP)
|
||||
return '{} {:.0f}°C'.format(ramp, temp.current)
|
||||
self.icon = Section.ramp(temp.current/temp.high, self.RAMP)
|
||||
if self.state >= 1:
|
||||
return '{:.0f}°C'.format(temp.current)
|
||||
|
||||
def __init__(self, theme=None, themeDanger=None, themeCritical=None):
|
||||
def __init__(self, theme=None):
|
||||
AlertingSection.__init__(self, theme)
|
||||
PeriodicUpdater.__init__(self)
|
||||
Section.__init__(self, theme=theme)
|
||||
self.themeNormal = theme or self.theme
|
||||
self.themeDanger = themeDanger or self.theme
|
||||
self.themeCritical = themeCritical or self.theme
|
||||
self.changeInterval(5)
|
||||
|
||||
|
||||
class BatteryProvider(Section, PeriodicUpdater):
|
||||
# TODO Use AlertingSection
|
||||
|
||||
class BatteryProvider(AlertingSection, PeriodicUpdater):
|
||||
NUMBER_STATES = 2
|
||||
RAMP = ""
|
||||
|
||||
def fetcher(self):
|
||||
bat = psutil.sensors_battery()
|
||||
text = ''
|
||||
if not bat:
|
||||
return text
|
||||
if bat.power_plugged:
|
||||
text += ""
|
||||
text += Section.ramp(bat.percent/100, self.RAMP)
|
||||
if bat.percent < 100:
|
||||
text += ' {:.0f}%'.format(bat.percent)
|
||||
theme = self.themeCritical if bat.percent < 10 else \
|
||||
(self.themeDanger if bat.percent < 25 else self.themeNormal)
|
||||
self.updateTheme(theme)
|
||||
return text
|
||||
self.icon = None
|
||||
return None
|
||||
|
||||
def __init__(self, theme=None, themeDanger=None, themeCritical=None):
|
||||
self.icon = ("" if bat.power_plugged else "") + \
|
||||
Section.ramp(bat.percent/100, self.RAMP)
|
||||
|
||||
self.updateLevel(1-bat.percent/100)
|
||||
|
||||
if self.state < 1:
|
||||
return
|
||||
|
||||
return Text('{:.0f}%'.format(bat.percent))
|
||||
# TODO Time remaining (if the estimation is somewhat correct)
|
||||
|
||||
def __init__(self, theme=None):
|
||||
AlertingSection.__init__(self, theme)
|
||||
PeriodicUpdater.__init__(self)
|
||||
Section.__init__(self, theme)
|
||||
self.themeNormal = theme or self.theme
|
||||
self.themeDanger = themeDanger or self.theme
|
||||
self.themeCritical = themeCritical or self.theme
|
||||
self.changeInterval(5)
|
||||
|
||||
|
||||
|
||||
class PulseaudioProvider(Section, ThreadedUpdater):
|
||||
def __init__(self, theme=None):
|
||||
ThreadedUpdater.__init__(self)
|
||||
|
@ -227,7 +229,7 @@ class PulseaudioProvider(Section, ThreadedUpdater):
|
|||
|
||||
class NetworkProviderSection(StatefulSection, Updater):
|
||||
|
||||
NUMBER_STATES = 4
|
||||
NUMBER_STATES = 5
|
||||
|
||||
def actType(self):
|
||||
self.ssid = None
|
||||
|
@ -269,6 +271,7 @@ class NetworkProviderSection(StatefulSection, Updater):
|
|||
return None
|
||||
|
||||
text = []
|
||||
self.persistent = True
|
||||
self.actType()
|
||||
|
||||
if self.showSsid and self.ssid:
|
||||
|
@ -302,10 +305,10 @@ class NetworkProviderSection(StatefulSection, Updater):
|
|||
return ' '.join(text)
|
||||
|
||||
def onChangeState(self, state):
|
||||
self.showSsid = state >= 0
|
||||
self.showAddress = state >= 1
|
||||
self.showSpeed = state >= 2
|
||||
self.showTransfer = state >= 3
|
||||
self.showSsid = state >= 1
|
||||
self.showAddress = state >= 2
|
||||
self.showSpeed = state >= 3
|
||||
self.showTransfer = state >= 4
|
||||
|
||||
def __init__(self, iface, parent):
|
||||
Updater.__init__(self)
|
||||
|
@ -408,7 +411,7 @@ class KeystoreProvider(Section, MergedUpdater):
|
|||
MergedUpdater.__init__(self, SshAgentProvider(), GpgAgentProvider())
|
||||
Section.__init__(self, theme)
|
||||
|
||||
class NotmuchUnreadProvider(ColorCountsSection, PeriodicUpdater):
|
||||
class NotmuchUnreadProvider(ColorCountsSection, InotifyUpdater):
|
||||
# TODO OPTI Transform InotifyUpdater (watching notmuch folder should be
|
||||
# enough)
|
||||
COLORABLE_ICON = ''
|
||||
|
@ -444,7 +447,7 @@ class NotmuchUnreadProvider(ColorCountsSection, PeriodicUpdater):
|
|||
color = f.read().strip()
|
||||
self.colors[account] = color
|
||||
|
||||
self.changeInterval(10)
|
||||
self.addPath(os.path.join(self.dir, '.notmuch', 'xapian'))
|
||||
|
||||
|
||||
class TodoProvider(ColorCountsSection, InotifyUpdater):
|
||||
|
@ -453,12 +456,24 @@ class TodoProvider(ColorCountsSection, InotifyUpdater):
|
|||
COLORABLE_ICON = ''
|
||||
|
||||
def updateCalendarList(self):
|
||||
print(459)
|
||||
calendars = sorted(os.listdir(self.dir))
|
||||
for calendar in calendars:
|
||||
# If the calendar wasn't in the list
|
||||
if calendar not in self.calendars:
|
||||
self.addPath(os.path.join(self.dir, calendar), refresh=False)
|
||||
|
||||
# Fetching name
|
||||
path = os.path.join(self.dir, calendar, 'displayname')
|
||||
with open(path, 'r') as f:
|
||||
self.names[calendar] = f.read().strip()
|
||||
|
||||
# Fetching color
|
||||
path = os.path.join(self.dir, calendar, 'color')
|
||||
with open(path, 'r') as f:
|
||||
self.colors[calendar] = f.read().strip()
|
||||
self.calendars = calendars
|
||||
print(475, self.calendars)
|
||||
|
||||
def __init__(self, dir, theme=None):
|
||||
"""
|
||||
|
@ -470,34 +485,37 @@ class TodoProvider(ColorCountsSection, InotifyUpdater):
|
|||
assert os.path.isdir(self.dir)
|
||||
|
||||
self.calendars = []
|
||||
self.addPath(self.dir)
|
||||
|
||||
def getName(self, calendar):
|
||||
path = os.path.join(self.dir, calendar, 'displayname')
|
||||
with open(path, 'r') as f:
|
||||
name = f.read().strip()
|
||||
return name
|
||||
|
||||
def getColor(self, calendar):
|
||||
path = os.path.join(self.dir, calendar, 'color')
|
||||
with open(path, 'r') as f:
|
||||
color = f.read().strip()
|
||||
return color
|
||||
self.colors = dict()
|
||||
self.names = dict()
|
||||
self.updateCalendarList()
|
||||
self.refreshData()
|
||||
|
||||
def countUndone(self, calendar):
|
||||
cmd = ["todo", "--porcelain", "list", self.getName(calendar)]
|
||||
cmd = ["todo", "--porcelain", "list"]
|
||||
if calendar:
|
||||
cmd.append(self.names[calendar])
|
||||
proc = subprocess.run(cmd, stdout=subprocess.PIPE)
|
||||
data = json.loads(proc.stdout)
|
||||
return len(data)
|
||||
|
||||
def subfetcher(self):
|
||||
counts = []
|
||||
self.updateCalendarList()
|
||||
|
||||
# TODO This an ugly optimisation that cuts on features, but todoman
|
||||
# calls are very expensive so we keep that in the meanwhile
|
||||
if self.state < 2:
|
||||
c = self.countUndone(None)
|
||||
if c > 0:
|
||||
counts.append((c, '#00000'))
|
||||
counts.append((0, '#FFFFF'))
|
||||
return counts
|
||||
# Optimisation ends here
|
||||
|
||||
for calendar in self.calendars:
|
||||
c = self.countUndone(calendar)
|
||||
if c <= 0:
|
||||
continue
|
||||
counts.append((c, self.getColor(calendar)))
|
||||
counts.append((c, self.colors[calendar]))
|
||||
return counts
|
||||
|
||||
class I3WindowTitleProvider(Section, I3Updater):
|
||||
|
@ -512,22 +530,42 @@ class I3WindowTitleProvider(Section, I3Updater):
|
|||
Section.__init__(self, theme=theme)
|
||||
self.on("window", self.on_window)
|
||||
|
||||
class I3WorkspacesProviderSection(Section):
|
||||
def selectTheme(self):
|
||||
if self.urgent:
|
||||
return self.parent.themeUrgent
|
||||
elif self.focused:
|
||||
return self.parent.themeFocus
|
||||
else:
|
||||
return self.parent.themeNormal
|
||||
|
||||
def show(self):
|
||||
self.updateTheme(self.selectTheme())
|
||||
self.updateText(self.fullName if self.focused else self.shortName)
|
||||
|
||||
def changeState(self, focused, urgent):
|
||||
self.focused = focused
|
||||
self.urgent = urgent
|
||||
self.show()
|
||||
|
||||
def setName(self, name):
|
||||
self.shortName = name
|
||||
self.fullName = self.parent.customNames[name] \
|
||||
if name in self.parent.customNames else name
|
||||
|
||||
def __init__(self, name, parent):
|
||||
Section.__init__(self)
|
||||
self.parent = parent
|
||||
self.setName(name)
|
||||
|
||||
def empty(self):
|
||||
self.updateTheme(self.parent.themeNormal)
|
||||
self.updateText(None)
|
||||
|
||||
|
||||
class I3WorkspacesProvider(Section, I3Updater):
|
||||
# TODO Multi-screen
|
||||
|
||||
THEME_NORMAL = 0
|
||||
THEME_FOCUSED = 2
|
||||
THEME_URGENT = 1
|
||||
THEME_MODE = 1
|
||||
|
||||
def setName(self, section, origName):
|
||||
# TODO Custom names
|
||||
if origName:
|
||||
section.fullName = origName
|
||||
else:
|
||||
section.fullName = ''
|
||||
section.updateText(section.fullName)
|
||||
|
||||
def initialPopulation(self, parent):
|
||||
"""
|
||||
Called on init
|
||||
|
@ -539,13 +577,14 @@ class I3WorkspacesProvider(Section, I3Updater):
|
|||
for workspace in workspaces:
|
||||
# if parent.display != workspace["display"]:
|
||||
# continue
|
||||
theme = self.themeFocus if workspace["focused"] \
|
||||
else (self.themeUrgent if workspace["urgent"]
|
||||
else self.theme)
|
||||
section = Section(theme=theme)
|
||||
|
||||
section = I3WorkspacesProviderSection(workspace["name"], self)
|
||||
section.focused = workspace["focused"]
|
||||
section.urgent = workspace["urgent"]
|
||||
section.show()
|
||||
parent.addSectionAfter(lastSection, section)
|
||||
self.setName(section, workspace["name"])
|
||||
self.sections[workspace["num"]] = section
|
||||
|
||||
lastSection = section
|
||||
|
||||
def on_workspace_init(self, i3, e):
|
||||
|
@ -554,45 +593,52 @@ class I3WorkspacesProvider(Section, I3Updater):
|
|||
if i in self.sections:
|
||||
section = self.sections[i]
|
||||
else:
|
||||
# Find the section just before
|
||||
while i not in self.sections.keys() and i > 0:
|
||||
i -= 1
|
||||
prevSection = self.sections[i] if i != 0 else self.modeSection
|
||||
section = Section()
|
||||
self.sections[workspace.num] = section
|
||||
|
||||
section = I3WorkspacesProviderSection(workspace.name, self)
|
||||
prevSection.appendAfter(section)
|
||||
self.setName(section, workspace.name)
|
||||
self.sections[workspace.num] = section
|
||||
section.focused = workspace.focused
|
||||
section.urgent = workspace.urgent
|
||||
section.show()
|
||||
|
||||
def on_workspace_empty(self, i3, e):
|
||||
workspace = e.current
|
||||
section = self.sections[workspace.num]
|
||||
self.setName(section, None)
|
||||
self.sections[e.current.num].empty()
|
||||
|
||||
def on_workspace_focus(self, i3, e):
|
||||
self.sections[e.current.num].updateTheme(self.themeFocus)
|
||||
self.sections[e.old.num].updateTheme(self.theme)
|
||||
self.sections[e.old.num].focused = False
|
||||
self.sections[e.old.num].show()
|
||||
self.sections[e.current.num].focused = True
|
||||
self.sections[e.current.num].show()
|
||||
|
||||
def on_workspace_urgent(self, i3, e):
|
||||
self.sections[e.current.num].updateTheme(self.themeUrgent)
|
||||
self.sections[e.current.num].urgent = e.current.urgent
|
||||
self.sections[e.current.num].show()
|
||||
|
||||
def on_workspace_rename(self, i3, e):
|
||||
self.sections[e.current.num].updateText(e.name)
|
||||
self.sections[e.current.num].setName(e.name)
|
||||
self.sections[e.current.num].show()
|
||||
|
||||
def on_mode(self, i3, e):
|
||||
if e.change == 'default':
|
||||
self.modeSection.updateText('')
|
||||
self.modeSection.updateText(None)
|
||||
for section in self.sections.values():
|
||||
section.updateText(section.fullName)
|
||||
section.show()
|
||||
else:
|
||||
self.modeSection.updateText(e.change)
|
||||
for section in self.sections.values():
|
||||
section.updateText('')
|
||||
section.empty()
|
||||
|
||||
def __init__(self, theme=0, themeFocus=3, themeUrgent=1, themeMode=2):
|
||||
def __init__(self, theme=0, themeFocus=3, themeUrgent=1, themeMode=2, customNames=dict()):
|
||||
I3Updater.__init__(self)
|
||||
Section.__init__(self)
|
||||
self.theme = theme
|
||||
self.themeNormal = theme
|
||||
self.themeFocus = themeFocus
|
||||
self.themeUrgent = themeUrgent
|
||||
self.customNames = customNames
|
||||
|
||||
self.sections = dict()
|
||||
self.on("workspace::init", self.on_workspace_init)
|
||||
|
|
|
@ -235,9 +235,8 @@ class MergedUpdater(Updater):
|
|||
text = Text()
|
||||
for updater in self.updaters:
|
||||
text.append(self.texts[updater])
|
||||
# TODO OPTI After Text.__len__
|
||||
# if not len(text):
|
||||
# return None
|
||||
if not len(text):
|
||||
return None
|
||||
return text
|
||||
|
||||
def __init__(self, *args):
|
||||
|
|
Loading…
Reference in a new issue