1
1
#!/usr/bin/python
2
2
3
3
# speedometer.py
4
- # Copyright (C) 2001-2011 Ian Ward
4
+ # Copyright (C) 2001-2012 Ian Ward
5
5
#
6
6
# This module is free software; you can redistribute it and/or
7
7
# modify it under the terms of the GNU Lesser General Public
13
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
14
# Lesser General Public License for more details.
15
15
16
- __version__ = "2.8 "
16
+ __version__ = "2.9 "
17
17
18
18
import time
19
19
import sys
@@ -200,8 +200,8 @@ def speed(self, *l, **d):
200
200
class EndOfData (Exception ):
201
201
pass
202
202
203
- class MultiGraphDisplay :
204
- def __init__ (self , cols , urwid_ui , exit_on_complete ):
203
+ class MultiGraphDisplay ( object ) :
204
+ def __init__ (self , cols , urwid_ui , exit_on_complete , shiny_colors ):
205
205
smoothed = urwid_ui == "smoothed"
206
206
self .displays = []
207
207
l = []
@@ -212,38 +212,40 @@ def __init__(self, cols, urwid_ui, exit_on_complete):
212
212
d = GraphDisplayProgress (tap , smoothed )
213
213
else :
214
214
d = GraphDisplay (tap , smoothed )
215
+ if shiny_colors :
216
+ d = ShinyMap (d , shiny_colors )
215
217
a .append (d )
216
218
self .displays .append (d )
217
219
l .append (a )
218
220
219
221
graphs = urwid .Columns ([urwid .Pile (a ) for a in l ], 1 )
220
222
graphs = urwid .AttrWrap (graphs , 'background' )
221
- title = urwid .Text ("Speedometer " + __version__ )
223
+ title = urwid .Text (" Speedometer " + __version__ )
222
224
title = urwid .AttrWrap (urwid .Filler (title ), 'title' )
223
225
self .top = urwid .Overlay (title , graphs ,
224
- ('fixed left' , 5 ), 16 , ('fixed top' , 0 ), 1 )
226
+ ('fixed left' , 5 ), 17 , ('fixed top' , 0 ), 1 )
225
227
226
228
self .urwid_ui = urwid_ui
227
229
self .exit_on_complete = exit_on_complete
228
230
229
231
palette = [
230
232
# name, 16-color fg, bg, mono fg, 88/256-color fg, bg
231
233
# main bar graph
232
- ('background' , 'dark gray' , '' , '' , '#008 ' , '#ddb' , ),
233
- ('bar:top' , 'dark cyan' , '' , '' , '#488' , '#ddb ' ),
234
- ('bar' , '' , 'dark cyan' ,'standout' , '#008' , '#488' ),
235
- ('bar:num' , '' , '' , '' , '#066' , '#ddb ' ),
234
+ ('background' , 'dark gray' , '' , '' , 'g20 ' , 'g70' ),
235
+ ('bar:top' , 'dark cyan' , '' , '' , '#488' , '' ),
236
+ ('bar' , '' , 'dark cyan' ,'standout' , '' , '#488' ),
237
+ ('bar:num' , '' , '' , '' , '#066' , 'g70 ' ),
236
238
# latest "curved" + average bar graph at right side
237
- ('ca:background' , '' , '' , '' , 'g66 ' , '#ddb ' ),
238
- ('ca:c:top' , 'dark blue' , '' , '' , '#66d' , '#ddb ' ),
239
- ('ca:c' , '' , 'dark blue' ,'standout' , 'g66' , '#66d' ),
240
- ('ca:c:num' , 'light blue' ,'' , '' , '#66d ' , '#ddb ' ),
241
- ('ca:a:top' , 'light gray' ,'' , '' , '#6b6' , '#ddb ' ),
242
- ('ca:a' , '' , 'light gray' ,'standout' ,'g66' , '#6b6' ),
243
- ('ca:a:num' , 'light gray' ,'' , 'bold' , '#6b6 ' , '#ddb ' ),
239
+ ('ca:background' , '' , '' , '' , '' , ' ' ),
240
+ ('ca:c:top' , 'dark blue' , '' , '' , '#66d' , '' ),
241
+ ('ca:c' , '' , 'dark blue' ,'standout' , '' , '#66d' ),
242
+ ('ca:c:num' , 'light blue' ,'' , '' , '#006 ' , 'g70 ' ),
243
+ ('ca:a:top' , 'light gray' ,'' , '' , '#6b6' , '' ),
244
+ ('ca:a' , '' , 'light gray' ,'standout' ,'' , '#6b6' ),
245
+ ('ca:a:num' , 'light gray' ,'' , 'bold' , '#060 ' , 'g70 ' ),
244
246
# text headings and numeric values displayed
245
- ('title' , '' , '' , 'underline,bold' , '#000 ' , '#ddb ' ),
246
- ('reading' , '' , '' , '' , '#886' , '#ddb ' ),
247
+ ('title' , '' , '' , 'underline,bold' , '#fff,bold ' , '#488 ' ),
248
+ ('reading' , '' , '' , '' , '#886' , 'g70 ' ),
247
249
# progress bar
248
250
('pr:n' , '' , 'dark blue' ,'' , 'g11' , '#bb6' ),
249
251
('pr:c' , '' , 'dark green' ,'standout' ,'g11' , '#fd0' ),
@@ -287,7 +289,7 @@ def update_callback(self, *args):
287
289
def update_readings (self ):
288
290
pending = 0
289
291
for d in self .displays :
290
- if d .update_readings (): pending += 1
292
+ if d .base_widget . update_readings (): pending += 1
291
293
return pending
292
294
293
295
def end_of_data (self ):
@@ -297,7 +299,7 @@ def end_of_data(self):
297
299
pass
298
300
299
301
300
- class GraphDisplay :
302
+ class GraphDisplay ( urwid . WidgetWrap ) :
301
303
def __init__ (self ,tap , smoothed ):
302
304
if smoothed :
303
305
self .speed_graph = SpeedGraph (
@@ -331,12 +333,7 @@ def __init__(self,tap, smoothed):
331
333
self .spd = Speedometer (6 )
332
334
self .feed = tap .feed
333
335
self .description = tap .description ()
334
-
335
- def selectable (self ):
336
- return False
337
-
338
- def render (self , size , focus = False ):
339
- return self .top .render (size ,focus )
336
+ super (GraphDisplay , self ).__init__ (self .top )
340
337
341
338
def update_readings (self ):
342
339
f = self .feed ()
@@ -771,7 +768,7 @@ class ArgumentError(Exception):
771
768
def console ():
772
769
"""Console mode"""
773
770
try :
774
- cols , urwid_ui , zero_files , exit_on_complete , num_colors = parse_args ()
771
+ cols , urwid_ui , zero_files , exit_on_complete , num_colors , shiny_colors = parse_args ()
775
772
except ArgumentError :
776
773
sys .stderr .write (__usage__ )
777
774
if not URWID_IMPORTED :
@@ -808,11 +805,11 @@ def console():
808
805
do_simple (tap .feed )
809
806
return
810
807
811
- do_display (cols , urwid_ui , exit_on_complete , num_colors )
808
+ do_display (cols , urwid_ui , exit_on_complete , num_colors , shiny_colors )
812
809
813
810
814
- def do_display (cols , urwid_ui , exit_on_complete , num_colors ):
815
- mg = MultiGraphDisplay (cols , urwid_ui , exit_on_complete )
811
+ def do_display (cols , urwid_ui , exit_on_complete , num_colors , shiny_colors ):
812
+ mg = MultiGraphDisplay (cols , urwid_ui , exit_on_complete , shiny_colors )
816
813
mg .main (num_colors )
817
814
818
815
@@ -875,6 +872,7 @@ def parse_args():
875
872
exit_on_complete = False
876
873
num_colors = 16
877
874
colors_set = False
875
+ shiny_colors = None
878
876
cols = []
879
877
taps = []
880
878
@@ -931,6 +929,8 @@ def push_tap(tap, taps):
931
929
assert num_colors in VALID_NUM_COLORS
932
930
except :
933
931
raise ArgumentError
932
+ if num_colors > 16 :
933
+ shiny_colors = num_colors
934
934
colors_set = True
935
935
936
936
elif op [:2 ] == "-i" :
@@ -1011,7 +1011,7 @@ def push_tap(tap, taps):
1011
1011
if chart_maximum <= chart_minimum :
1012
1012
raise ArgumentError
1013
1013
1014
- return cols , urwid_ui , zero_files , exit_on_complete , num_colors
1014
+ return cols , urwid_ui , zero_files , exit_on_complete , num_colors , shiny_colors
1015
1015
1016
1016
1017
1017
def do_simple (feed ):
@@ -1087,6 +1087,66 @@ def wait_all(cols):
1087
1087
for tap in c :
1088
1088
tap .wait_creation ()
1089
1089
1090
+ def shiny (y ):
1091
+ """
1092
+ return a value between 0 (dark) and 1 (bright) for a given y position
1093
+ between 0 (top) and 1 (bottom) to create a "shiny" background effect
1094
+ """
1095
+ gamma = 1 - (4 * (y - 0.25 )) ** 2 if y < 0.5 else (2 * y - 1 ) ** 2
1096
+ return max (0 , min (1 , (gamma - 0.2 )* 1.2 ))
1097
+
1098
+ class ShinyMap (urwid .WidgetPlaceholder ):
1099
+ def __init__ (self , w , colors ):
1100
+ assert colors in (88 , 256 )
1101
+ self ._colors = colors
1102
+ super (ShinyMap , self ).__init__ (w )
1103
+ self ._shiny_cache = []
1104
+ self ._shiny_cache_maxrow = None
1105
+
1106
+ def _rebuild_shiny_cache (self , maxrow ):
1107
+ prev_gray = None
1108
+ if self ._shiny_cache_maxrow == maxrow :
1109
+ return
1110
+ self ._shiny_cache = []
1111
+ self ._shiny_cache_maxrow = maxrow
1112
+ for y in range (maxrow ):
1113
+ gamma = shiny (1 - (y + 0.5 )/ maxrow )
1114
+ if self ._colors == 256 :
1115
+ gamma = gamma * 25 + 10
1116
+ else :
1117
+ gamma = gamma * 45
1118
+ spec = urwid .AttrSpec ('g70' , 'g%d' % gamma , self ._colors )
1119
+ gray = spec .background
1120
+ if prev_gray == gray :
1121
+ amap , num = self ._shiny_cache [- 1 ]
1122
+ self ._shiny_cache [- 1 ] = amap , num + 1
1123
+ continue
1124
+ prev_gray = gray
1125
+ amap = {
1126
+ 'background' : spec ,
1127
+ 'bar:top' : urwid .AttrSpec ('#488' , gray , self ._colors ),
1128
+ 'reading' : spec ,
1129
+ 'ca:background' : spec ,
1130
+ 'ca:c:top' : urwid .AttrSpec ('#66d' , gray , self ._colors ),
1131
+ 'ca:a:top' : urwid .AttrSpec ('#6b6' , gray , self ._colors ),
1132
+ }
1133
+ self ._shiny_cache .append ((amap , 1 ))
1134
+
1135
+ def render (self , size , focus = False ):
1136
+ maxcol , maxrow = size
1137
+ canv = super (ShinyMap , self ).render (size , focus )
1138
+ self ._rebuild_shiny_cache (maxrow )
1139
+ slivers = []
1140
+ y = 0
1141
+ for amap , run in self ._shiny_cache :
1142
+ c = urwid .CompositeCanvas (canv )
1143
+ c .trim (y , run )
1144
+ y = y + run
1145
+ c .fill_attr_apply (amap )
1146
+ slivers .append ((c , None , False ))
1147
+ return urwid .CanvasCombine (slivers )
1148
+
1149
+
1090
1150
1091
1151
if __name__ == "__main__" :
1092
1152
try :
0 commit comments