1+ # -*- coding: utf-8 -*-
12from __future__ import absolute_import
23from __future__ import division
34from __future__ import print_function
@@ -743,7 +744,109 @@ def __call__(self, progress, data):
743744 self , progress , self .mapping , self .format )
744745
745746
746- class Variable (FormatWidgetMixin , WidgetBase ):
747+ class VariableMixin (object ):
748+ '''Mixin to display a custom user variable '''
749+
750+ def __init__ (self , name , ** kwargs ):
751+ if not isinstance (name , str ):
752+ raise TypeError ('Variable(): argument must be a string' )
753+ if len (name .split ()) > 1 :
754+ raise ValueError ('Variable(): argument must be single word' )
755+ self .name = name
756+
757+
758+ class MultiRangeBar (Bar , VariableMixin ):
759+ '''
760+ A bar with multiple sub-ranges, each represented by a different symbol
761+
762+ The various ranges are represented on a user-defined variable, formatted as
763+
764+ .. code-block:: python
765+
766+ [
767+ ['Symbol1', amount1],
768+ ['Symbol2', amount2],
769+ ...
770+ ]
771+ '''
772+
773+ def __init__ (self , name , markers , ** kwargs ):
774+ VariableMixin .__init__ (self , name )
775+ Bar .__init__ (self , ** kwargs )
776+ self .markers = [
777+ string_or_lambda (marker )
778+ for marker in markers
779+ ]
780+
781+ def get_values (self , progress , data ):
782+ return data ['variables' ][self .name ] or []
783+
784+ def __call__ (self , progress , data , width ):
785+ '''Updates the progress bar and its subcomponents'''
786+
787+ left = converters .to_unicode (self .left (progress , data , width ))
788+ right = converters .to_unicode (self .right (progress , data , width ))
789+ width -= progress .custom_len (left ) + progress .custom_len (right )
790+ values = self .get_values (progress , data )
791+
792+ values_sum = sum (values )
793+ if width and values_sum :
794+ middle = ''
795+ values_accumulated = 0
796+ width_accumulated = 0
797+ for marker , value in zip (self .markers , values ):
798+ marker = converters .to_unicode (marker (progress , data , width ))
799+ assert utils .len_color (marker ) == 1
800+
801+ values_accumulated += value
802+ item_width = int (values_accumulated / values_sum * width )
803+ item_width -= width_accumulated
804+ width_accumulated += item_width
805+ middle += item_width * marker
806+ else :
807+ fill = converters .to_unicode (self .fill (progress , data , width ))
808+ assert utils .len_color (fill ) == 1
809+ middle = fill * width
810+
811+ return left + middle + right
812+
813+
814+ class MultiProgressBar (MultiRangeBar ):
815+ def __init__ (self ,
816+ name ,
817+ # NOTE: the markers are not whitespace even though some
818+ # terminals don't show the characters correctly!
819+ markers = ' ▁▂▃▄▅▆▇█' ,
820+ ** kwargs ):
821+ MultiRangeBar .__init__ (self , name = name ,
822+ markers = list (reversed (markers )), ** kwargs )
823+
824+ def get_values (self , progress , data ):
825+ ranges = [0 ] * len (self .markers )
826+ for progress in data ['variables' ][self .name ] or []:
827+ if not isinstance (progress , (int , float )):
828+ # Progress is (value, max)
829+ progress_value , progress_max = progress
830+ progress = float (progress_value ) / float (progress_max )
831+
832+ if progress < 0 or progress > 1 :
833+ raise ValueError (
834+ 'Range value needs to be in the range [0..1], got %s' %
835+ progress )
836+
837+ range_ = progress * (len (ranges ) - 1 )
838+ pos = int (range_ )
839+ frac = range_ % 1
840+ ranges [pos ] += (1 - frac )
841+ if (frac ):
842+ ranges [pos + 1 ] += (frac )
843+
844+ if self .fill_left :
845+ ranges = list (reversed (ranges ))
846+ return ranges
847+
848+
849+ class Variable (FormatWidgetMixin , VariableMixin , WidgetBase ):
747850 '''Displays a custom variable.'''
748851
749852 def __init__ (self , name , format = '{name}: {formatted_value}' ,
@@ -752,14 +855,9 @@ def __init__(self, name, format='{name}: {formatted_value}',
752855 self .format = format
753856 self .width = width
754857 self .precision = precision
755- if not isinstance (name , str ):
756- raise TypeError ('Variable(): argument must be a string' )
757- if len (name .split ()) > 1 :
758- raise ValueError ('Variable(): argument must be single word' )
858+ VariableMixin .__init__ (self , name = name )
759859 WidgetBase .__init__ (self , ** kwargs )
760860
761- self .name = name
762-
763861 def __call__ (self , progress , data ):
764862 value = data ['variables' ][self .name ]
765863 context = data .copy ()
0 commit comments