#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright © 2019 Michael J. Hayford
""" Definitions for user interface actions
`Action` classes are those that contain a `dict` called ``actions``. The
``actions`` dict contains functions that are executed for UI actions
corresponding to the keyword.
Action keywords include:
'press'
'drag'
'release'
The argument lists for the called functions include ``fig`` and ``event``.
Duck typing is relied on loosen the binding with a particular GUI
implementation - or at least that's the theory.
``fig`` must support a function refresh_gui()
.. Created on Wed Apr 24 14:26:14 2019
.. codeauthor: Michael J. Hayford
"""
import math
from opticalglass import glassfactory as gfact
[docs]class Action():
""" Action built on a set/get function pair """
def __init__(self, getf, setf):
self.getf = getf
self.setf = setf
self.cur_value = None
self.new_value = None
self.actions = {}
def on_select(fig, event):
self.cur_value = getf()
return self.cur_value
self.actions['press'] = on_select
def on_edit(fig, event, new_value):
setf(self.cur_value, new_value)
fig.refresh_gui()
self.actions['drag'] = on_edit
def on_release(fig, event):
self.new_value = getf()
fig.refresh_gui()
self.actions['release'] = on_release
[docs]class AttrAction():
""" Action built on an object/attribute pair """
def __init__(self, obj, attr):
self.object = obj
self.attr = attr
self.cur_value = getattr(self.object, self.attr, None)
self.new_value = None
self.actions = {}
def on_select(fig, event):
self.cur_value = getattr(self.object, self.attr, None)
# print('AttrAction.on_select:', self.attr, self.cur_value)
return self.cur_value
self.actions['press'] = on_select
def on_edit(fig, event, delta_value):
setattr(self.object, self.attr, self.cur_value+delta_value)
# print('AttrAction.on_edit:', self.attr, self.cur_value+delta_value)
fig.refresh_gui()
self.actions['drag'] = on_edit
def on_release(fig, event):
self.new_value = getattr(self.object, self.attr, None)
fig.refresh_gui()
self.actions['release'] = on_release
[docs]class SagAction():
""" Action to set the profile_cv via surface sag (related to x,y input) """
def __init__(self, surf):
self.surf = surf
self.cur_value = None
self.new_value = None
self.actions = {}
def on_select(fig, event):
self.cur_value = self.surf.z_sag((event.x, event.ydata))
# print('SagAction.on_select:', self.cur_value)
return self.cur_value
self.actions['press'] = on_select
def on_edit(fig, event, value):
self.surf.set_z_sag(value)
# cv = self.surf.calc_cv_from_zsag(value)
# print('SagAction.on_edit (x, y, cv):', value, cv)
fig.refresh_gui()
self.actions['drag'] = on_edit
def on_release(fig, event):
self.new_value = self.surf.z_sag((event.x, event.ydata))
fig.refresh_gui()
self.actions['release'] = on_release
[docs]class BendAction():
""" Action to bend a lens element, using x component of user input """
def __init__(self, e):
self.ele = e
self.select_pt_lcl = None
self.cv_orig = None
self.cv_new = None
self.actions = {}
def sag(cv, y):
if cv != 0.0:
r = 1/cv
adj = math.sqrt(r*r - y*y)
return r*(1 - abs(adj/r))
else:
return 0
def on_select(fig, event):
self.select_pt_lcl = event.lcl_pt
self.cv_orig = self.ele.reference_interface().profile_cv
self.xsag_orig = sag(self.cv_orig, event.lcl_pt[1])
# print('on_select: {:.3f} {:.3f} {:.5f}'
# .format(event.lcl_pt[0], self.xsag_orig, self.cv_orig))
return self.select_pt_lcl
self.actions['press'] = on_select
def on_edit(fig, event, lcl_pt):
cv1 = self.ele.s1.profile_cv
cv2 = self.ele.s2.profile_cv
x, y = lcl_pt
xsag_new = self.xsag_orig + (x - self.select_pt_lcl[0])
new_pt = xsag_new, lcl_pt[1]
cv1_new = self.ele.reference_interface().calc_cv_from_zsag(new_pt)
# print('on_edit: {:.3f} {:.3f} {:.5f}'.format(x, xsag_new, cv1_new))
delta_cv = cv1_new - cv1
cv2_new = cv2 + delta_cv
self.ele.s1.profile_cv = cv1_new
self.ele.s2.profile_cv = cv2_new
fig.refresh_gui()
self.actions['drag'] = on_edit
def on_release(fig, event):
self.cv_new = self.ele.reference_interface().profile_cv
xsag = sag(self.cv_new, event.lcl_pt[1])
# print('on_release: {:.3f} {:.3f} {:.5f}'
# .format(event.lcl_pt[0], xsag, self.cv_new))
fig.refresh_gui()
self.actions['release'] = on_release
[docs]class ReplaceGlassAction():
""" Action for replacing an element's glass from a drag/drop action. """
def __init__(self, gap, update=True):
self.gap = gap
self.update = update
self.actions = {}
def null_action(fig, event):
pass
self.actions['press'] = null_action
self.actions['drag'] = null_action
self.actions['release'] = null_action
def __call__(self, fig, event):
mime = event.mimeData()
# comma separated list
glass_name, catalog_name = mime.text().split(',')
mat = gfact.create_glass(glass_name, catalog_name)
self.gap.medium = mat
if self.update:
fig.refresh_gui()