#export
class ImageButton(VBox, HasTraits):
"""
Represents simple image with label and toggle button functionality.
# Class methods
- clear(): Clear image infos
- on_click(p_function): Handle click events
# Class methods
- clear(): Clear image infos
- on_click(p_function): Handle click events
- reset_callbacks(): Reset event callbacks
"""
debug_output = Output(layout={'border': '1px solid black'})
active = Bool()
image_path = Unicode()
label_value = Unicode()
def __init__(self, setting: ImageButtonSetting):
self.setting = setting
self.image = Image(
layout=Layout(display='flex',
justify_content='center',
align_items='center',
align_content='center',
width=setting.image_width,
margin='0 0 0 0',
height=setting.image_height),
)
if self.setting.display_label: # both image and label
self.setting.label = HTML(
value='?',
layout=Layout(display='flex',
justify_content='center',
align_items='center',
align_content='center'),
)
else: # no label (capture image case)
self.im_name = self.setting.im_name
self.im_index = self.setting.im_index
self.image.layout.border = 'solid 1px gray'
self.image.layout.object_fit = 'contain'
self.image.margin = '0 0 0 0'
self.image.layout.overflow = 'hidden'
super().__init__(layout=Layout(align_items='center',
margin='3px',
overflow='hidden',
padding='2px'))
if not setting.im_path:
self.clear()
self.d = Event(source=self, watched_events=['click'])
@observe('image_path')
def _read_image(self, change=None):
new_path = change['new']
if new_path:
self.image.value = open(new_path, "rb").read()
if not self.children:
self.children = (self.image,)
if self.setting.display_label:
self.children += (self.setting.label,)
else:
#do not display image widget
self.children = tuple()
@observe('label_value')
def _read_label(self, change=None):
new_label = change['new']
if isinstance(self.setting.label, HTML):
self.setting.label.value = new_label
else:
self.setting.label = new_label
def clear(self):
if isinstance(self.setting.label, HTML):
self.setting.label.value = ''
else:
self.setting.label = ''
self.image_path = ''
self.active = False
@observe('active')
def mark(self, ev):
# pad to compensate self size with border
if self.active:
active_color = '#f7f01e'
padding = '0px'
if self.setting.display_label:
self.layout.border = f'solid 2px {active_color}'
self.layout.padding = padding
else:
self.image.layout.border = f'solid 3px {active_color}'
self.image.layout.padding = padding
else:
if self.setting.display_label:
self.layout.border = 'none'
self.layout.padding = '2px'
else:
self.image.layout.border = 'solid 1px gray'
def __eq__(self, other):
equals = [
other.image_path == self.image_path,
other.label_value == self.label_value,
other.active == self.active,
]
return all(equals)
def update(self, other):
if self != other:
self.image_path = other.image_path
self.label_value = other.label_value
self.active = other.active
@property
def value(self):
return Path(self.image_path).name
@debug_output.capture(clear_output=False)
def on_click(self, cb):
self.d.on_dom_event(cb)
def reset_callbacks(self):
self.d.reset_callbacks()