summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Connors <benconnors@outlook.com>2019-10-25 13:24:41 -0400
committerBen Connors <benconnors@outlook.com>2019-10-25 13:24:41 -0400
commit2cb483c4812eee903295f76f30aaac0b429245d1 (patch)
tree875b78c2a93809f4edfa43dd35255e2f6e62be8b
parent084b8dce9c1219bb14ed109c5e1c9ae6680d8455 (diff)
Add preliminary chaser viewer
-rwxr-xr-xinterface/channelbank.py2
-rwxr-xr-xinterface/chaserview.py140
-rw-r--r--interface/interface.py15
3 files changed, 152 insertions, 5 deletions
diff --git a/interface/channelbank.py b/interface/channelbank.py
index c7c7409..e3dec7b 100755
--- a/interface/channelbank.py
+++ b/interface/channelbank.py
@@ -125,8 +125,6 @@ class ChannelBank:
self.win.erase()
ncv = {}
cols = (self._width-4)//ChannelView.width
- with open("out.txt", 'w+') as f:
- f.write(str(cols)+'\n')
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
diff --git a/interface/chaserview.py b/interface/chaserview.py
new file mode 100755
index 0000000..2c88343
--- /dev/null
+++ b/interface/chaserview.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python3
+
+import curses
+import math
+import threading
+
+import blc2
+from blc2.constants import INFTY
+
+CURSES_LOCK = threading.RLock()
+
+def format_time(n):
+ if n == INFTY:
+ return "∞s"
+ elif n == 0:
+ return "0s"
+ postfixes = "mcisahkegtp"
+ idx = 0
+ multiple = 10
+ while n >= multiple:
+ idx += 1
+ multiple *= 10
+
+ return str(n)[0]+postfixes[idx]
+
+class ChaserView:
+ def set_dim(self, height, width):
+ if height < 5 or width < 10:
+ raise ValueError("Size too small")
+
+ with self._lock:
+ if (height, width) != (self._height, self._width):
+ self.win.erase()
+ self.win.noutrefresh()
+
+ self.win.resize(height, width)
+ self.win.redrawwin()
+
+ self._height = height
+ self._width = width
+ self._redraw()
+
+ @staticmethod
+ def fit(s, l, pad=False):
+ ## TODO: Try shortening by words first?
+ if len(s) > l:
+ return s[:l-1] + '…'
+ elif len(s) < l and pad:
+ return s + ' '*(l-len(s))
+ return s
+
+ def set_pos(self, y, x):
+ with self._lock:
+ if (y, x) != (self._y, self._x):
+ self.win.mvwin(y, x)
+ self._y = y
+ self._x = x
+ self.win.noutrefresh()
+
+ def _redraw(self):
+ self.win.erase()
+ self.win.border()
+ self.win.hline(2, 1, curses.ACS_HLINE, self._width-2)
+ self.win.addch(2, 0, curses.ACS_LTEE)
+ self.win.addch(2, self._width-1, curses.ACS_RTEE)
+
+ if self._chaser is None:
+ self.win.refresh()
+ return
+
+ c = self._chaser
+ w = self._width - 2
+ self.win.addstr(1, 1, self.fit(("%d: "% c.id) + c.name, w-2))
+
+ maxsteps = self._height - 4
+ if maxsteps < len(c.steps):
+ if self._selected is None:
+ steps = c.steps[:maxsteps]
+ else:
+ last = min(self._selected + (maxsteps // 2), len(c.steps))
+ first = last - maxsteps
+ if first < 0:
+ last -= first
+ first = 0
+ else:
+ first = 0
+ last = len(c.steps)
+ steps = c.steps[first:last]
+ for n, s in enumerate(steps, 1):
+ if s.index == self._selected:
+ attrs = curses.A_REVERSE
+ else:
+ attrs = 0
+ t = "%s:%s:%s" % (format_time(s.fade_in), format_time(s.duration), format_time(s.fade_out))
+ self.win.addstr(n+2, 1, self.fit((self._numformat % (s.index+1)) + ": " + s.name, w-8, pad=True)+t, attrs)
+
+ if first > 0:
+ self.win.addch(3, self._width//2, '⯅')
+ if last < len(c.steps):
+ self.win.addch(self._height-1, self._width//2, '⯆')
+
+ self.win.refresh()
+
+ @property
+ def selected(self):
+ with self._lock:
+ return self._selected
+
+ @selected.setter
+ def selected(self, value):
+ with self._lock:
+ if value != self._selected:
+ self._selected = value
+ ## TODO: Clean this up if possible?
+ self._redraw()
+
+ def set_chaser(self, chaser, selected=None):
+ with self._lock:
+ self._chaser = chaser
+ self._selected = selected
+ if chaser is not None and chaser.steps:
+ self._numformat = "%%%dd" % math.ceil(math.log10(len(chaser.steps)))
+ self._redraw()
+
+ def __init__(self, y, x, height, width):
+ with CURSES_LOCK:
+ self.win = curses.newwin(height, width, y, x)
+ self.win.keypad(True)
+ self._lock = threading.RLock()
+ self._height = height
+ self._width = width
+ self._y = -1
+ self._x = -1
+
+ self._chaser = None
+ self._numformat = ""
+ self._selected = -1
+
+ self.set_pos(y, x)
+ self.set_dim(height, width)
diff --git a/interface/interface.py b/interface/interface.py
index b838b08..65cd1d2 100644
--- a/interface/interface.py
+++ b/interface/interface.py
@@ -18,6 +18,7 @@ from blc2.workspace import Workspace
from .globals import CURSES_LOCK
from .input.tabcomp import Input
from .channelbank import ChannelBank
+from .chaserview import ChaserView
from .pager import Pager
def wrap_curses(f):
@@ -40,21 +41,25 @@ class Interface:
(ht, width), (0, 0),
(4, wr), (height-4, wl+1),
(hb - 4, wr), (ht, wl+1),
+ (hb, wl//2 - 1), (ht, 0),
+ (hb, wl - (wl//2)), (ht, wl//2)
)
def _resize(self):
- for a, f in zip(self._compute_sizes(*self.stdscr.getmaxyx()), (self.channel_bank.set_dim, self.channel_bank.set_pos, self.input.set_dim, self.input.set_pos, self.pager.set_dim, self.pager.set_pos)):
+ for a, f in zip(self._compute_sizes(*self.stdscr.getmaxyx()), (self.channel_bank.set_dim, self.channel_bank.set_pos, self.input.set_dim, self.input.set_pos, self.pager.set_dim, self.pager.set_pos, self.chaser_views[0].set_dim, self.chaser_views[0].set_pos, self.chaser_views[1].set_dim, self.chaser_views[1].set_pos)):
f(*a)
@wrap_curses
def main(self, stdscr):
height, width = stdscr.getmaxyx()
self.stdscr = stdscr
- cbd, cbp, ind, inp, pgd, pgp = self._compute_sizes(height, width)
+ cbd, cbp, ind, inp, pgd, pgp, cv0d, cv0p, cv1d, cv1p = self._compute_sizes(height, width)
self.channel_bank = ChannelBank(*cbp, *cbd)
self.input = Input(*inp, *ind)
self.input.context = self.context_base
self.pager = Pager(*pgp, *pgd)
+ self.chaser_views[0] = ChaserView(*cv0p, *cv0d)
+ self.chaser_views[1] = ChaserView(*cv1p, *cv1d)
todisp = [
"=== Welcome to BLC2!",
@@ -156,7 +161,9 @@ class Interface:
with self.w_lock:
td = ["FIXTURES:"]
for f in sorted(self.w.fixtures.values(), key=lambda a: a.id):
- td.append("- %03d; %3dc: %s" % (f.id, len(f.channels), f.name))
+ td.append("- %03d: %s" % (f.id, f.name))
+ for c in f.channels:
+ td.append(" %03d-%03d: %s" % (f.id, c.id, c.name))
self.pager.display_many(td, split=True)
def list_functions(self, typ):
@@ -214,6 +221,8 @@ class Interface:
self.w_lock = threading.RLock()
+ self.chaser_views = [None, None]
+
self.context_base = Input.parse_context((
("edit $num", self.base_edit),
("delete $num", self.base_delete),