# Copyright 2016 Autodesk Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import collections
import ipywidgets as ipy
from moldesign.uibase import UnitText, ReadOnlyRepr
from moldesign import utils
def exports(o):
__all__.append(o.__name__)
return o
__all__ = []
@exports
[docs]class Configurator(ipy.Box):
""" Interactive configuration widget for a list of parameters
Args:
paramlist (Mapping[str,object]): Mapping of parameter names to their current values
paramdefs (Mapping[str,Parameter]): Mapping of parameter names to their definitions
Attributes:
selectors (Mapping[str,ParamSelector]): Mapping of parameters names to their selector
widgets
"""
# TODO: help text. Use javascript to show/hide? http://stackoverflow.com/a/1313353/1958900
def __init__(self, paramlist, paramdefs, title=None):
super(Configurator, self).__init__(layout=ipy.Layout(display='flex',
flex_flow='column',
align_self='flex-start',
align_items='stretch',
max_width='100%'))
self.paramlist = paramlist
self.paramdefs = paramdefs
self.apply_button = ipy.Button(description='Apply')
self.apply_button.on_click(self.apply_values)
self.reset_button = ipy.Button(description='Reset')
self.reset_button.on_click(self.reset_values)
self.buttons = ipy.Box([self.reset_button, self.apply_button],
layout=ipy.Layout(align_self='center'))
self.selectors = collections.OrderedDict([(p.name, ParamSelector(p)) for p in paramdefs])
self.reset_values()
title = utils.if_not_none(title, 'Configuration')
self.title = ipy.HTML('<center><h4>%s</h4></center><hr>' % title,
align_self='center')
self.currentconfig = ipy.Textarea(description='Current params:',
disabled=True,
value=str(paramlist).replace(', ', ',\n '),
width='350px')
self.middle = ipy.HBox([ipy.VBox(self.selectors.values()), self.currentconfig])
self.children = [self.title, self.middle, self.buttons]
[docs] def reset_values(self, *args):
reset_params = set()
for name, value in self.paramlist.iteritems():
if value is not None:
self.selectors[name].selector.value = value
reset_params.add(name)
for paramdef in self.paramdefs:
if paramdef.name not in reset_params: # if it's not set already, make it the default
self.selectors[paramdef.name].default()
self.show_relevant_fields()
[docs] def apply_values(self, *args):
for paramname, selector in self.selectors.iteritems():
self.paramlist[paramname] = selector.selector.value
self.currentconfig.value = str(self.paramlist).replace(', ', ',\n ')
self.show_relevant_fields()
[docs] def show_relevant_fields(self):
for s in self.selectors.itervalues():
if s.paramdef.relevance is not None:
if s.paramdef.relevance(self.paramlist):
s.layout.visibility = 'visible'
else:
s.layout.visibility = 'hidden'
class ParamSelector(ipy.Box):
WIDGETKWARGS = {'width': '200px'}
def __init__(self, paramdef):
super(ParamSelector, self).__init__(layout=ipy.Layout(display='flex',
flex_flow='nowrap',
align_content='baseline'))
self.paramdef = paramdef
children = []
self.name = ipy.HTML("<p style='text-align:right'>%s:</p>" % paramdef.displayname,
width='200px')
children.append(self.name)
if paramdef.choices:
self.selector = ipy.Dropdown(options=paramdef.choices, **self.WIDGETKWARGS)
elif paramdef.type == bool:
self.selector = ipy.ToggleButtons(options=[True, False], **self.WIDGETKWARGS)
elif paramdef.units:
self.selector = UnitText(units=paramdef.units, **self.WIDGETKWARGS)
elif paramdef.type == float:
self.selector = ipy.FloatText(**self.WIDGETKWARGS)
elif paramdef.type == int:
self.selector = ipy.IntText(**self.WIDGETKWARGS)
elif paramdef.type == str:
self.selector = ipy.Text(**self.WIDGETKWARGS)
else:
self.selector = ReadOnlyRepr(**self.WIDGETKWARGS)
children.append(self.selector)
children = [self.name, self.selector]
self.default_button = None
if paramdef.default:
self.default_button = ipy.Button(description='Default',
tooltip='Set to default: %s' % self.paramdef.default,
width='75px')
self.default_button.on_click(self.default)
children.append(self.default_button)
self.default()
self.help_link = None
if paramdef.help_url:
self.help_link = ipy.HTML('<a href="%s" target="_blank">?</a>' % paramdef.help_url)
children.append(self.help_link)
self.children = children
def default(self, *args):
self.selector.value = self.paramdef.default
@property
def value(self):
return self.selector.value
@value.setter
def value(self, v):
self.selector.value = v