Mercurial > code > home > repos > light9
annotate light9/dmxchanedit.py @ 1922:11e2f63bb2f2
more stats to measure sequencer framerate better
Ignore-this: 5df74b41a9847296432a31d248b31857
author | Drew Perttula <drewp@bigasterisk.com> |
---|---|
date | Sat, 01 Jun 2019 23:43:44 +0000 |
parents | 3c523c71da29 |
children |
rev | line source |
---|---|
0 | 1 """ |
2 | |
3 widget to show all dmx channel levels and allow editing. levels might | |
4 not actually match what dmxserver is outputting. | |
5 | |
803 | 6 proposal for new focus and edit system: |
7 - rows can be selected | |
8 - the chan number or label can be used to select rows. dragging over rows brings all of them into or out of the current selection | |
9 - numbers drag up and down (like today) | |
10 - if you drag a number in a selected row, all the selected numbers change | |
11 - if you start dragging a number in an unselected row, your row becomes the new selection and then the edit works | |
12 | |
13 | |
14 proposal for new attribute system: | |
15 - we always want to plan some attributes for each light: where to center; what stage to cover; what color gel to apply; whether the light is burned out | |
16 - we have to stop packing these into the names. Names should be like 'b33' or 'blue3' or just '44'. maybe 'blacklight'. | |
17 | |
0 | 18 """ |
1859
f066d6e874db
2to3 with these fixers: all idioms set_literal
drewp@bigasterisk.com
parents:
1858
diff
changeset
|
19 |
f066d6e874db
2to3 with these fixers: all idioms set_literal
drewp@bigasterisk.com
parents:
1858
diff
changeset
|
20 import tkinter as tk |
1866
3c523c71da29
pyflakes cleanups and some refactors
Drew Perttula <drewp@bigasterisk.com>
parents:
1859
diff
changeset
|
21 from rdflib import RDF |
1157
dc86936969d8
SC don't break so much on corrupt subs (but we don't yet remove their dangling graph links)
drewp@bigasterisk.com
parents:
979
diff
changeset
|
22 import math, logging |
910
3a15fb921b9c
more tripleFilter speedups. accept Decimals coming in from n3 files, which happens with the 2012 code
Drew Perttula <drewp@bigasterisk.com>
parents:
838
diff
changeset
|
23 from decimal import Decimal |
803 | 24 from light9.namespaces import L9 |
1157
dc86936969d8
SC don't break so much on corrupt subs (but we don't yet remove their dangling graph links)
drewp@bigasterisk.com
parents:
979
diff
changeset
|
25 log = logging.getLogger('dmxchanedit') |
1264 | 26 stdfont = ('Arial', 7) |
231 | 27 |
1858 | 28 |
29 def gradient(lev, low=(80, 80, 180), high=(255, 55, 50)): | |
30 out = [int(l + lev * (h - l)) for h, l in zip(high, low)] | |
31 col = "#%02X%02X%02X" % tuple(out) | |
32 return col | |
33 | |
231 | 34 |
0 | 35 class Onelevel(tk.Frame): |
803 | 36 """a name/level pair |
37 | |
38 source data is like this: | |
39 ch:b11-c a :Channel; | |
40 :output dmx:c54; | |
41 rdfs:label "b11-c" . | |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
42 |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
43 and the level is like this: |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
44 |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
45 ?editor :currentSub ?sub . |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
46 ?sub :lightLevel [:channel ?ch; :level ?level] . |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
47 |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
48 levels come in with self.setTo and go out by the onLevelChange |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
49 callback. This object does not use the graph for level values, |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
50 which I'm doing for what I think is efficiency. Unclear why I |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
51 didn't use Observable for that API. |
803 | 52 """ |
1858 | 53 |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
54 def __init__(self, parent, graph, channelUri, onLevelChange): |
1858 | 55 tk.Frame.__init__(self, parent, height=20) |
803 | 56 self.graph = graph |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
57 self.onLevelChange = onLevelChange |
803 | 58 self.uri = channelUri |
1858 | 59 self.currentLevel = 0 # the level we're displaying, 0..1 |
0 | 60 |
803 | 61 # no statement yet |
62 self.channelnum = int( | |
1858 | 63 self.graph.value(self.uri, L9['output']).rsplit('/c')[-1]) |
803 | 64 |
0 | 65 # 3 widgets, left-to-right: |
66 | |
67 # channel number -- will turn yellow when being altered | |
1858 | 68 self.num_lab = tk.Label(self, |
69 text=str(self.channelnum), | |
70 width=3, | |
71 bg='grey40', | |
334
42e4c4728a66
ascoltami, subcomposer, keyboardcomposer use rdf show data; raise channel count to 270
drewp@bigasterisk.com
parents:
320
diff
changeset
|
72 fg='white', |
42e4c4728a66
ascoltami, subcomposer, keyboardcomposer use rdf show data; raise channel count to 270
drewp@bigasterisk.com
parents:
320
diff
changeset
|
73 font=stdfont, |
1858 | 74 padx=0, |
75 pady=0, | |
76 bd=0, | |
77 height=1) | |
0 | 78 self.num_lab.pack(side='left') |
79 | |
80 # text description of channel | |
1858 | 81 self.desc_lab = tk.Label(self, |
82 width=14, | |
83 font=stdfont, | |
84 anchor='w', | |
85 padx=0, | |
86 pady=0, | |
87 bd=0, | |
88 height=1, | |
89 bg='black', | |
90 fg='white') | |
805
54732a2f9935
SC more specific handler for faster chan label updates
drewp@bigasterisk.com
parents:
804
diff
changeset
|
91 self.graph.addHandler(self.updateLabel) |
0 | 92 self.desc_lab.pack(side='left') |
210
f41004d5a507
factored out some networking, new show/ layout, curvecalc works
drewp@bigasterisk.com
parents:
209
diff
changeset
|
93 |
0 | 94 # current level of channel, shows intensity with color |
1858 | 95 self.level_lab = tk.Label(self, |
96 width=3, | |
97 bg='lightBlue', | |
98 anchor='e', | |
99 font=stdfont, | |
100 padx=1, | |
101 pady=0, | |
102 bd=0, | |
103 height=1) | |
0 | 104 self.level_lab.pack(side='left') |
105 | |
106 self.setupmousebindings() | |
805
54732a2f9935
SC more specific handler for faster chan label updates
drewp@bigasterisk.com
parents:
804
diff
changeset
|
107 |
54732a2f9935
SC more specific handler for faster chan label updates
drewp@bigasterisk.com
parents:
804
diff
changeset
|
108 def updateLabel(self): |
1858 | 109 self.desc_lab.config(text=self.graph.label(self.uri)) |
821 | 110 |
0 | 111 def setupmousebindings(self): |
1858 | 112 |
0 | 113 def b1down(ev): |
114 self.desc_lab.config(bg='cyan') | |
1858 | 115 self._start_y = ev.y |
116 self._start_lev = self.currentLevel | |
117 | |
0 | 118 def b1motion(ev): |
1858 | 119 delta = self._start_y - ev.y |
120 self.setlevel(max(0, min(1, self._start_lev + delta * .005))) | |
121 | |
0 | 122 def b1up(ev): |
123 self.desc_lab.config(bg='black') | |
1858 | 124 |
205
3905d3c92aaa
twisted mainloop, more row-change keys, xmlrpc fadesub command on port 8050
drewp
parents:
201
diff
changeset
|
125 def b3up(ev): |
803 | 126 self.setlevel(0.0) |
1858 | 127 |
205
3905d3c92aaa
twisted mainloop, more row-change keys, xmlrpc fadesub command on port 8050
drewp
parents:
201
diff
changeset
|
128 def b3down(ev): |
803 | 129 self.setlevel(1.0) |
1858 | 130 |
131 def b2down(ev): # same thing for now | |
803 | 132 self.setlevel(1.0) |
0 | 133 |
134 # make the buttons work in the child windows | |
135 for w in self.winfo_children(): | |
1858 | 136 for e, func in (('<ButtonPress-1>', |
137 b1down), ('<B1-Motion>', | |
138 b1motion), ('<ButtonRelease-1>', b1up), | |
139 ('<ButtonPress-2>', | |
140 b2down), ('<ButtonRelease-3>', | |
141 b3up), ('<ButtonPress-3>', b3down)): | |
320
fd06667e00e1
b2 light setting in subcomposer
Drew Perttula <drewp@bigasterisk.com>
parents:
231
diff
changeset
|
142 |
1858 | 143 w.bind(e, func) |
821 | 144 |
0 | 145 def colorlabel(self): |
146 """color the level label based on its own text (which is 0..100)""" | |
1858 | 147 txt = self.level_lab['text'] or "0" |
148 lev = float(txt) / 100 | |
231 | 149 self.level_lab.config(bg=gradient(lev)) |
0 | 150 |
803 | 151 def setlevel(self, newlev): |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
152 """UI received a level change, which we put in the graph""" |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
153 self.onLevelChange(self.uri, newlev) |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
154 |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
155 def setTo(self, newLevel): |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
156 """levelbox saw a change in the graph""" |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
157 self.currentLevel = min(1, max(0, newLevel)) |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
158 newLevel = "%d" % (self.currentLevel * 100) |
1858 | 159 olddisplay = self.level_lab.cget('text') |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
160 if newLevel != olddisplay: |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
161 self.level_lab.config(text=newLevel) |
0 | 162 self.colorlabel() |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
163 |
0 | 164 |
803 | 165 class Levelbox(tk.Frame): |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
166 """ |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
167 this also watches all the levels in the sub and sets the boxes when they change |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
168 """ |
1858 | 169 |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
170 def __init__(self, parent, graph, currentSub): |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
171 """ |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
172 currentSub is an Observable(PersistentSubmaster) |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
173 """ |
1858 | 174 tk.Frame.__init__(self, parent) |
0 | 175 |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
176 self.currentSub = currentSub |
803 | 177 self.graph = graph |
178 graph.addHandler(self.updateChannels) | |
0 | 179 |
1858 | 180 self.currentSub.subscribe(lambda _: graph.addHandler(self. |
181 updateLevelValues)) | |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
182 |
803 | 183 def updateChannels(self): |
184 """(re)make Onelevel boxes for the defined channels""" | |
185 | |
186 [ch.destroy() for ch in self.winfo_children()] | |
1858 | 187 self.levelFromUri = {} # channel : OneLevel |
0 | 188 |
803 | 189 chans = list(self.graph.subjects(RDF.type, L9.Channel)) |
1858 | 190 chans.sort( |
191 key=lambda c: int(self.graph.value(c, L9.output).rsplit('/c')[-1])) | |
803 | 192 cols = 2 |
979
c1f3cc23b51b
subcomposer wouldn't draw right if there is an odd number of channels
drewp@bigasterisk.com
parents:
910
diff
changeset
|
193 rows = int(math.ceil(len(chans) / cols)) |
0 | 194 |
803 | 195 def make_frame(parent): |
1858 | 196 f = tk.Frame(parent, bd=0, bg='black') |
197 f.pack(side='left') | |
198 return f | |
821 | 199 |
803 | 200 columnFrames = [make_frame(self) for x in range(cols)] |
201 | |
1858 | 202 for i, channel in enumerate(chans): # sort? |
0 | 203 # frame for this channel |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
204 f = Onelevel(columnFrames[i // rows], self.graph, channel, |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
205 self.onLevelChange) |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
206 |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
207 self.levelFromUri[channel] = f |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
208 f.pack(side='top') |
0 | 209 |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
210 def updateLevelValues(self): |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
211 """set UI level from graph""" |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
212 submaster = self.currentSub() |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
213 if submaster is None: |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
214 return |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
215 sub = submaster.uri |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
216 if sub is None: |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
217 raise ValueError("currentSub is %r" % submaster) |
0 | 218 |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
219 remaining = set(self.levelFromUri.keys()) |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
220 for ll in self.graph.objects(sub, L9['lightLevel']): |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
221 chan = self.graph.value(ll, L9['channel']) |
1157
dc86936969d8
SC don't break so much on corrupt subs (but we don't yet remove their dangling graph links)
drewp@bigasterisk.com
parents:
979
diff
changeset
|
222 try: |
1858 | 223 lev = self.graph.value(ll, L9['level']).toPython() |
1157
dc86936969d8
SC don't break so much on corrupt subs (but we don't yet remove their dangling graph links)
drewp@bigasterisk.com
parents:
979
diff
changeset
|
224 except AttributeError as e: |
1858 | 225 log.error('on lightlevel %r:', ll) |
226 log.exception(e) | |
227 continue | |
910
3a15fb921b9c
more tripleFilter speedups. accept Decimals coming in from n3 files, which happens with the 2012 code
Drew Perttula <drewp@bigasterisk.com>
parents:
838
diff
changeset
|
228 if isinstance(lev, Decimal): |
1858 | 229 lev = float(lev) |
1859
f066d6e874db
2to3 with these fixers: all idioms set_literal
drewp@bigasterisk.com
parents:
1858
diff
changeset
|
230 assert isinstance(lev, (int, float)), repr(lev) |
1157
dc86936969d8
SC don't break so much on corrupt subs (but we don't yet remove their dangling graph links)
drewp@bigasterisk.com
parents:
979
diff
changeset
|
231 try: |
1858 | 232 self.levelFromUri[chan].setTo(lev) |
233 remaining.remove(chan) | |
1157
dc86936969d8
SC don't break so much on corrupt subs (but we don't yet remove their dangling graph links)
drewp@bigasterisk.com
parents:
979
diff
changeset
|
234 except KeyError as e: |
1858 | 235 log.exception(e) |
838
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
236 for channel in remaining: |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
237 self.levelFromUri[channel].setTo(0) |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
238 |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
239 def onLevelChange(self, chan, newLevel): |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
240 """UI received a change which we put in the graph""" |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
241 if self.currentSub() is None: |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
242 raise ValueError("no currentSub in Levelbox") |
321fc6150ee3
subcomposer's nice currently-editing DnD box
drewp@bigasterisk.com
parents:
821
diff
changeset
|
243 self.currentSub().editLevel(chan, newLevel) |