qmsk/dmx/web.py
changeset 83 136e210fce82
parent 82 b5878197d017
child 84 9ebf1a2cee3a
equal deleted inserted replaced
82:b5878197d017 83:136e210fce82
     1 import pvl.web
     1 import pvl.web
     2 from pvl.web import urls, html
     2 from pvl.web import urls, html
     3 
     3 
     4 import logging; log = logging.getLogger('qmsk.dmx.web')
     4 import logging; log = logging.getLogger('qmsk.dmx.web')
       
     5 
       
     6 def colorize (x, red, green, blue, alpha=1.0) :
       
     7     return x(style='background-color: rgba({red}, {green}, {blue}, {alpha:0.2f})'.format(red=red, green=green, blue=blue, alpha=alpha))
       
     8 
       
     9 def input (head, name, value) :
       
    10     return html.input(
       
    11             type        = 'text',
       
    12             name        = '-'.join([head, name]),
       
    13 
       
    14             id          = '-'.join([head, name]),
       
    15             class_      = 'form-control dmx-input dmx-input-{name}'.format(name=name),
       
    16 
       
    17             placeholder = name,
       
    18             value       = '{v:d}'.format(v=value) if value else None,
       
    19     )
       
    20 
       
    21 def color_input (head, c, value) :
       
    22     color = dict(red=0, green=0, blue=0, alpha=0)
       
    23 
       
    24     color[c] = 255
       
    25     if value :
       
    26         color[alpha] = value / 255.0
       
    27 
       
    28     return colorize(input(head, c, value), **color)
       
    29 
       
    30 def slider (head, name) :
       
    31     return html.div(id='-'.join([head, name, 'slider']), class_='dmx-slider dmx-slider-{name}'.format(name=name))
       
    32 
       
    33 def color_slider (head, c) :
       
    34     return slider(head, c)
       
    35 
       
    36 def head_color (head, value) :
       
    37     return html.div(class_='dmx-color-background')(colorize(html.div(id='-'.join([head, 'color']), class_='dmx-color')(' '), **value))
     5 
    38 
     6 class Handler (pvl.web.Handler) :
    39 class Handler (pvl.web.Handler) :
     7     # Bootstrap
    40     # Bootstrap
     8     DOCTYPE = 'html'
    41     DOCTYPE = 'html'
     9     HTML_XMLNS = None
    42     HTML_XMLNS = None
    10     HTML_LANG = 'en'
    43     HTML_LANG = 'en'
    11     CSS = (
    44     CSS = (
    12             '//code.jquery.com/ui/1.10.4/themes/ui-darkness/jquery-ui.css',
    45             '//code.jquery.com/ui/1.10.4/themes/ui-darkness/jquery-ui.css',
    13             '//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css',
    46             '//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css',
       
    47 
       
    48             '/static/dmx.css',
    14     )
    49     )
    15     JS = (
    50     JS = (
    16             '//code.jquery.com/jquery-2.1.0.js',
    51             '//code.jquery.com/jquery-2.1.0.js',
    17             '//code.jquery.com/ui/1.10.4/jquery-ui.js',
    52             '//code.jquery.com/ui/1.10.4/jquery-ui.js',
    18             '//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js',
    53             '//netdna.bootstrapcdn.com/bootstrap/3.0.3/js/bootstrap.min.js',
    19             
    54             
    20             '/static/color-slider.js',
    55             '/static/color-slider.js',
       
    56             '/static/dmx.js',
    21     )
    57     )
    22 
       
    23     STYLE = """
       
    24 body {
       
    25     padding-top: 2em;
       
    26     text-align: center;
       
    27 }
       
    28 
       
    29 .container {
       
    30     padding: 2em 1em;
       
    31     text-align: left;
       
    32 }
       
    33 
       
    34 .panel {
       
    35     width: 30em;
       
    36     margin: 1em auto;
       
    37 }
       
    38 
       
    39 input.color-control {
       
    40     width: 5em;
       
    41 }
       
    42 
       
    43 div#color {
       
    44     width: 5em;
       
    45     height: 5em;
       
    46 
       
    47     margin: 1em auto;
       
    48 }
       
    49 
       
    50 div.color-slider {
       
    51     margin: 1em;
       
    52 }
       
    53 
       
    54 div.color-slider#slider-r .ui-slider-range {
       
    55     background: #ff0000;
       
    56 }
       
    57 
       
    58 div.color-slider#slider-g .ui-slider-range {
       
    59     background: #00ff00;
       
    60 }
       
    61 
       
    62 div.color-slider#slider-b .ui-slider-range {
       
    63     background: #0000ff;
       
    64 }
       
    65     """
       
    66 
    58 
    67     # test
    59     # test
    68     TITLE = u"DMX Control"
    60     TITLE = u"DMX Control"
    69 
    61 
    70     def process (self) :
    62     def process (self) :
    71         if self.request.method == 'POST' :
    63         if self.request.method == 'POST' :
    72             self.color = tuple((int(x, 16) if x else 0) for x in (
    64             # XXX
       
    65             r, g, b = tuple((int(x, 16) if x else 0) for x in (
    73                     self.request.form.get('r'),
    66                     self.request.form.get('r'),
    74                     self.request.form.get('g'),
    67                     self.request.form.get('g'),
    75                     self.request.form.get('b'),
    68                     self.request.form.get('b'),
    76             ))
    69             ))
    77 
    70 
    78             r, g, b = self.color
       
    79 
       
    80             self.app.dmx_color(r, g, b, 255)
    71             self.app.dmx_color(r, g, b, 255)
    81 
    72 
       
    73     def render_head (self, name, head) :
       
    74         if head.alpha() is None :
       
    75             head_input = head_slider = None
    82         else :
    76         else :
    83             self.color = None
    77             head_input = input(name, 'alpha', head.alpha()['alpha'])
       
    78             head_slider = slider(name, 'alpha')
    84 
    79 
    85         log.info("%s", self.color)
    80         rowspan = 1
    86 
    81 
       
    82         if head.color() is None :
       
    83             colors = { }
       
    84             color = None
       
    85         else :
       
    86             colors = head.color()
       
    87             color = head_color(name, colors)
       
    88             rowspan += 3
       
    89 
       
    90         yield html.tr(
       
    91             html.th(rowspan=rowspan)(name),
       
    92             html.td(head_input),
       
    93             html.td(head_slider),
       
    94             html.td(rowspan=rowspan)(color),
       
    95         )
       
    96                 
       
    97         for c in colors :
       
    98             yield html.tr(
       
    99                 html.td(
       
   100                     color_input(name, c, colors[c]),
       
   101                 ),
       
   102                 html.td(
       
   103                     color_slider(name, c),
       
   104                 ),
       
   105             )
       
   106     
    87     def render (self) :
   107     def render (self) :
    88         if self.color :
   108         return html.div(class_='container')(
    89             r, g, b = self.color
   109             html.form(action='.', method='POST')(
    90         else :
   110                 html.table(class_='dmx')(
    91             r = g = b = None
   111                     html.thead(
       
   112                         html.th(class_='dmx-head')(u"Head"),
       
   113                         html.th(class_='dmx-value')(u"DMX"),
       
   114                         html.th(class_='dmx-control')(u"Control"),
       
   115                         html.th(class_='dmx-head-control')(u"Head Control"),
       
   116                     ),
       
   117                     html.tbody(self.render_head(name, head) for name, head in sorted(self.app.heads.iteritems())),
       
   118                 ),
    92 
   119 
    93         def color_swatch () :
   120                 html.button(type='submit', class_='btn btn-primary')("Go"),
    94             return html.div(id='color',
       
    95                     style='background-color: rgb({r}, {g}, {b})'.format(r=r, g=g, b=b)
       
    96             )(' '),
       
    97 
       
    98         def color_input (name, value) :
       
    99             color = dict(r=0, g=0, b=0)
       
   100             bgcolor = dict(r=0, g=0, b=0)
       
   101 
       
   102             if value :
       
   103                 color[name] = value
       
   104                 alpha = value / 255.0
       
   105             else :
       
   106                 alpha = 0
       
   107 
       
   108             bgcolor[name] = 255
       
   109 
       
   110             return html.input(type='text', name=name,
       
   111                     class_      = 'form-control color-control',
       
   112                     placeholder = name,
       
   113                     id          = name,
       
   114 
       
   115                     value   = '{v:02x}'.format(v=value) if value else None,
       
   116                     style   = 'background-color: rgba({r}, {g}, {b}, {a:0.2f})'.format(a=alpha, **bgcolor),
       
   117             )
       
   118 
       
   119         return html.div(class_='container')(
       
   120             html.div(class_='panel')(
       
   121                 color_swatch(),
       
   122                 html.div(id='slider-r', class_='color-slider')(' '),
       
   123                 html.div(id='slider-g', class_='color-slider')(' '),
       
   124                 html.div(id='slider-b', class_='color-slider')(' '),
       
   125                 html.form(action='.', method='POST', class_='form-inline')(
       
   126                        #html.label(for_='color', class_='control-label')("Color"),
       
   127                     html.div(class_='form-group')(
       
   128                        color_input('r', r),
       
   129                     ),
       
   130                     html.div(class_='form-group')(
       
   131                        color_input('g', g),
       
   132                     ),
       
   133                     html.div(class_='form-group')(
       
   134                        color_input('b', b),
       
   135                     ),
       
   136                     html.div(class_='form-group')(
       
   137                         html.button(type='submit', class_='btn btn-primary')("Go"),
       
   138                     ),
       
   139                 )
       
   140             )
   121             )
   141         )
   122         )
   142 
   123 
   143 class DMXWebApplication (pvl.web.Application) :
   124 class DMXWebApplication (pvl.web.Application) :
   144     URLS = urls.Map((
   125     URLS = urls.Map((
   145         urls.rule('/',          Handler),
   126         urls.rule('/',          Handler),
   146     ))
   127     ))
   147 
   128 
   148     def __init__ (self, dmx, **opts) :
   129     def __init__ (self, dmx, heads, **opts) :
   149         super(DMXWebApplication, self).__init__(**opts)
   130         super(DMXWebApplication, self).__init__(**opts)
   150 
   131 
   151         self.dmx = dmx
   132         self.dmx = dmx
   152 
   133         self.heads = heads
   153     def dmx_color (self, r, g, b, a=255) :
       
   154         # Stairville LED Par56
       
   155         self.dmx[1] = (0, r, g, b, 0)
       
   156 
       
   157         # 4ch dimmer
       
   158         self.dmx[5] = (a, a, a, a)
       
   159 
       
   160         # American DJ - Mega Tri 60 - Mode 2
       
   161         self.dmx[10] = (r, g, b, 0, a)