import curses from .globals import CURSES_LOCK _progress = [" "] for i in range(8): pos = i // 2 s = _progress[-1] _progress.append(s[:pos] + ('\u2588' if i%2 else '\u258c') + s[pos+1:]) def get_progress(v): if v == 0: return _progress[0] elif v <= 36: return _progress[1] elif v <= 73: return _progress[2] elif v <= 109: return _progress[3] elif v <= 145: return _progress[4] elif v <= 181: return _progress[5] elif v <= 218: return _progress[6] elif v <= 254: return _progress[7] return _progress[8] class ChannelView: width = 9 height = 3 def _refresh_channel(self): with CURSES_LOCK: self.win.addstr(0, 0, "%03d.%03d" % (self.c.f.id, self.c.id), curses.A_UNDERLINE if self._active else 0) self.win.refresh() def _refresh_value(self): with CURSES_LOCK: self.win.addstr(1, 0, get_progress(self._value)) self.win.addstr(1, 4, "%03d" % self._value, (curses.A_ITALIC|curses.A_BOLD if self._held else 0)) self.win.refresh() def refresh(self): self._refresh_value() self._refresh_channel() @property def active(self): return self._active @active.setter def active(self, v): if v != self._active: self._active = v self._refresh_channel() @property def value(self): return self._value @value.setter def value(self, v): if v != self._value: self._value = v self._refresh_value() @property def held(self): return self._held @held.setter def held(self, v): if v != self._held: self._held = v self._refresh_value() def set_pos(self, y, x): self.y = self.y self.x = self.x with CURSES_LOCK: self.win.refresh() self.win.mvwin(y, x) self.refresh() def __init__(self, root, c, y, x, value=0, held=False, active=False): self._active = active self._held = held self._value = value self.c = c self.y = y self.x = x self.root = root with CURSES_LOCK: self.win = root.subpad(self.height, self.width, self.y, self.x) self.win.leaveok(True) self._refresh_value() self._refresh_channel() class ChannelBank: def set_dim(self, height, width): if ((height-2)//ChannelView.height) * ((width-4)//ChannelView.width) < len(self.scope): raise NotImplementedError("Screen size to small") with CURSES_LOCK: if (height, width) != (self._height, self._width): self.win.erase() self.win.refresh() self.win.resize(height, width) self.win.redrawwin() self._height = height self._width = width self._refresh_scope() self._put_title() self.win.refresh() def _refresh_scope(self): with CURSES_LOCK: self.win.erase() ncv = {} cols = (self._width-4)//ChannelView.width self._sscope = sorted(self.scope, key=lambda a: (a.f.id, a.id)) for n, c in enumerate(self._sscope): row = (n // cols)*ChannelView.height + 1 col = (n % cols)*ChannelView.width + 2 if c in self._cv: active = self._cv[c].active held = self._cv[c].held value = self._cv[c].value else: active = False held = False value = 0 ncv[c] = ChannelView(self.win, c, row, col, value=value, active=active, held=held) self._cv = ncv self._put_title() self.win.refresh() def set_pos(self, y, x): if (y, x) != (self._y, self._x): with CURSES_LOCK: self.win.mvwin(y, x) self._put_title() self.win.refresh() def set_active(self, channels, v=True): for c in channels: self._cv[c].active = v def set_held(self, channels, v=True): for c in channels: self._cv[c].held = v def set_values(self, cv): if isinstance(cv, dict): cv = cv.items() for c, v in cv: self._cv[c].value = v def set_scope(self, scope): self.scope = frozenset(scope) self._refresh_scope() @property def title(self): return self._title def _put_title(self): self.win.border() pos = min(self._width-2-len(self._title), (3*self._width)//4 - (len(self._title) // 2)) self.win.addstr(self._height-1, pos, self._title, curses.A_REVERSE if self._highlight else 0) @property def highlight(self): return self._highlight @highlight.setter def highlight(self, value): if value != self._highlight: self._highlight = value with CURSES_LOCK: self._put_title() self.win.refresh() @title.setter def title(self, v): if v != self._title: with CURSES_LOCK: self._title = v self.win.border() self._put_title() self.win.refresh() def __init__(self, y, x, height, width, scope=frozenset()): with CURSES_LOCK: self.win = curses.newwin(height, width, y, x) self.win.keypad(True) self._highlight = False self.scope = frozenset(scope) self._sscope = [] self._title = "Channels" self._cv = {} self._height = height self._width = width self._y = -1 self._x = -1 self.set_pos(y, x) self.set_dim(height, width)