#!/usr/bin/env python import os import wx import math import empty import thr import dbg str_to_evt = lambda s: eval( 'wx.EVT_' + s ) mouse_evt_strs = [ 'LEFT_DOWN', 'LEFT_UP', 'MIDDLE_DOWN', 'MIDDLE_UP', 'RIGHT_DOWN', 'RIGHT_UP', 'MOTION', ] mouse_evts = list( map( str_to_evt, mouse_evt_strs ) ) key_evt_strs = [ 'KEY_DOWN', 'KEY_UP', ] key_evts = list( map( str_to_evt, key_evt_strs ) ) etc_evt_strs = [ 'BUTTON', 'TOGGLEBUTTON', 'CHECKBOX', 'CHOICE', 'CLOSE', ] etc_evts = list( map( str_to_evt, etc_evt_strs ) ) evt_strs = mouse_evt_strs + key_evt_strs + etc_evt_strs evts = list( map( str_to_evt, evt_strs ) ) evt_str_dic = dict( zip( evts, evt_strs ) ) typeId_evt_dic = dict( map( lambda evt: ( evt.typeId, evt ), evts ) ) cls_evt_dic = { wx.Button: wx.EVT_BUTTON, wx.ToggleButton: wx.EVT_TOGGLEBUTTON, wx.CheckBox: wx.EVT_CHECKBOX, wx.Choice: wx.EVT_CHOICE, wx.TextCtrl: [ wx.EVT_TEXT_ENTER, wx.EVT_SET_FOCUS ], wx.Slider: wx.EVT_SLIDER, } def drag_new(o): def btn_stat_new(btn): e = empty.new( x=None, y=None ) def update(act, x, y): ret = None if act == 'DOWN': (e.x, e.y) = ( x, y ) ret = empty.new( o=o, btn=btn, act=act, sx=x, sy=y, ex=x, ey=y ) elif act in ('MOTION', 'UP') and e.x != None and e.y != None: ret = empty.new( o=o, btn=btn, act=act, sx=e.x, sy=e.y, ex=x, ey=y ) if act == 'UP': (e.x, e.y) = ( None, None ) return ret return empty.to_attr( e, locals() ) btns = [ 'LEFT', 'MIDDLE', 'RIGHT' ] stats = list( map( btn_stat_new, btns ) ) dic = dict( zip( btns, stats ) ) def update(inf): if inf.o != o: return None s = evt_str_dic.get( inf.evt ) if s == 'MOTION': for btn_stat in stats: v = btn_stat.update( s, inf.x, inf.y ) if v: return v if '_' in s: (btn, act) = s.split( '_' ) if btn in btns: btn_stat = dic.get( btn ) return btn_stat.update( act, inf.x, inf.y ) return None return empty.new( locals() ) def post_evt(obj, evt): ev = wx.PyCommandEvent( evt.typeId, obj.GetId() ) ev.SetEventObject( obj ) wx.PostEvent( obj, ev ) def exp_path( path='', DIR='${IINO_DIR}' ): if '$' in path: path = os.path.expandvars( path ) if path[ 0 ] != '/' and not os.path.exists( path ): path = os.path.join( DIR, path ) path = os.path.expandvars( path ) return path def new(title, init, fini=None, args=None, on_init=None): e = empty.new( app=None, frame=None, args=args, on_init=on_init ) newed_objs = {} def newed_obj_set(k, o): newed_objs[ k ] = o return o def wp(o, **kwds): dv = empty.new( border=4, prop=0, flag=0 ) for (k, v) in vars( dv ).items(): if k not in kwds: kwds[ k ] = v kwds[ 'o' ] = o return empty.new( kwds ) def wp_exp(o, **kwds): kwds[ 'flag' ] = kwds.get( 'flag', 0 ) | wx.EXPAND return wp( o, **kwds ) def to_wp(o): if empty.is_empty( o ): return o if type( o ) == str: o = newed_obj_set( o, label_new( o ) ) return wp( o ) def wrap(win, lsts): vsz = wx.BoxSizer( wx.VERTICAL ) for o_v in lsts: hsz = wx.BoxSizer( wx.HORIZONTAL ) wp_v = to_wp( o_v ) lst = wp_v.o for o_h in lst: wp_h = to_wp( o_h ) #wp_h.flag |= wx.LEFT | wx.ALIGN_CENTER_VERTICAL wp_h.flag |= wx.LEFT if o_h == lst[ -1 ]: wp_h.flag |= wx.RIGHT hsz.Add( wp_h.o, wp_h.prop, wp_h.flag, wp_h.border ) wp_v.flag |= wx.TOP if o_v == lsts[ -1 ]: wp_v.flag |= wx.BOTTOM vsz.Add( hsz, wp_v.prop, wp_v.flag, wp_v.border ) win.SetSizer( vsz ) def wrap_frame(lsts): wrap( e.frame, lsts ) obj_cls_dic = {} def wx_new(cls, *args, **kwds): prm = empty.kwds_pop( kwds, min_w=-1, min_h=-1, parent=None ) if prm.parent == None: prm.parent = e.frame o = cls( prm.parent, wx.ID_ANY, *args, **kwds ) obj_cls_dic[ o ] = cls if prm.min_w != -1 or prm.min_h != -1: o.SetMinSize( ( prm.min_w, prm.min_h ) ) return o bind_dic = {} def ev_inf_new(ev, o, typeId, evt, wxo): v = empty.attr_call( o, 'GetValue', () ) label = empty.attr_call( o, 'GetLabel', (), '' ) (x, y) = empty.attr_call( ev, 'GetPosition', (), ( 0, 0 ) ) return empty.new( locals() ) def bind_hdl(ev): o = ev.GetEventObject() typeId = ev.GetEventType() k = ( o, typeId ) if k in bind_dic: (evt, hdl) = bind_dic.get( k ) inf = ev_inf_new( ev, o, typeId, evt, e ) # e as wxo if hdl: hdl( inf ) def bind(o, hdl, evt=None): if evt == None: cls = obj_cls_dic.get( o ) evt = cls_evt_dic.get( cls ) if type( o ) == list: f = lambda o: bind( o, hdl, evt ) return list( map( f, o ) ) if type( evt ) == list: f = lambda evt: bind( o, hdl, evt ) return list( map( f, evt ) ) k = ( o, evt.typeId ) bind_dic[ k ] = ( evt, hdl ) return o.Bind( evt, bind_hdl ) obj_dic = {} def bind_obj_dic_hdl(o, hdl): p = obj_dic.get( o ) if p: p.hdl = hdl def drag_hdl(inf): p = obj_dic.get( inf.o ) (drag, hdl) = ( p.drag, p.hdl ) dr = drag.update( inf ) if dr and hdl: inf.dr = dr hdl( inf ) def set_drag_hdl(o, hdl): if type( o ) == list: f = lambda o: set_drag_hdl( o, hdl ) return list( map( f, o ) ) obj_dic[ o ] = empty.new( drag=drag_new( o ), hdl=hdl ) bind( o, drag_hdl, mouse_evts ) def label_new(s, **kwds): if type( s ) == list: f = lambda s: label_new( s, **kwds ) return list( map( f, s ) ) return wx_new( wx.StaticText, s, style=wx.ALIGN_CENTER, **kwds ) def button_new(lbl, hdl=None, **kwds): if type( lbl ) == list: f = lambda lbl: button_new( lbl, hdl, **kwds ) return list( map( f, lbl ) ) btn = wx_new( wx.Button, lbl, **kwds ) if hdl: bind( btn, hdl ) return btn def checkbox_new(lbl, hdl=None, init_stat=False, **kwds): if type( lbl ) == list: f = lambda lbl: checkbox_new( lbl, hdl, init_stat, **kwds ) return list( map( f, lbl ) ) ckb = wx_new( wx.CheckBox, lbl, **kwds ) if init_stat: ckb.SetValue( init_stat ) if hdl: bind( ckb, hdl ) return ckb def menu_get(menu): p = obj_dic.get( menu ) (lbls, hdl, vs) = ( p.lbls, p.hdl, p.vs ) i = menu.GetSelection() lbl = p.lbls[ i ] v = vs[ i ] if vs and i < len( vs ) else None return empty.new( i=i, lbl=lbl, v=v ) def menu_set( menu, lbls, init_str='', vs=None ): menu.SetItems( lbls ) if not init_str: init_str = lbls[ 0 ] menu.SetStringSelection( init_str ) p = obj_dic.get( menu ) p.lbls = lbls p.vs = vs def menu_hdl(inf): menu = inf.o p = obj_dic.get( menu ) if p.hdl: inf.menu = menu_get( menu ) p.hdl( inf ) def menu_new(lbls, hdl=None, init_str='', vs=None, **kwds): menu = wx_new( wx.Choice, choices=lbls, **kwds ) if not init_str: init_str = lbls[ 0 ] menu.SetStringSelection( init_str ) obj_dic[ menu ] = empty.new( lbls=lbls, hdl=hdl, vs=vs ) bind( menu, menu_hdl ) return menu def menu_bind(menu, hdl): bind_obj_dic_hdl( menu, hdl ) def menu_int_new( v_min, v_max, hdl=None, v_init=None, **kwds ): vs = range( v_min, v_max + 1 ) lbls = list( map( str, vs ) ) init_str = '' if v_init is not None: init_str = str( v_init ) return menu_new( lbls, hdl, init_str, vs, **kwds ) def toggle_lbl(lbls, v): if type( lbls ) == list: i = 1 if len( lbls ) >= 2 and v else 0 return lbls[ i ] return lbls # str def toggle_hdl(inf): tbtn = inf.o p = obj_dic.get( tbtn ) lbl = toggle_lbl( p.lbls, inf.v ) tbtn.SetLabel( lbl ) inf.label = lbl if p.hdl: p.hdl( inf ) def toggle_new(lbls, hdl=None, init_stat=False, **kwds): tbtn = wx_new( wx.ToggleButton, toggle_lbl( lbls, init_stat ), **kwds ) if init_stat: tbln.SetValue( init_state ) obj_dic[ tbtn ] = empty.new( lbls=lbls, hdl=hdl ) bind( tbtn, toggle_hdl ) return tbtn def toggle_bind(tbtn, hdl): bind_obj_dic_hdl( tbtn, hdl ) def tc_new( s, hdl=None ): tc = wx_new( wx.TextCtrl, s, style=wx.TE_PROCESS_ENTER ) bind( tc, hdl ) return tc def tc_num_new( v, qtz_exp='0.01', hdl=None ): qtz = lambda v: dbg.quantize( v, qtz_exp ) def hdl_tc( inf ): tc = inf.o try: inf.v = str( qtz( inf.v ) ) tc.SetValue( inf.v ) except: return if hdl: hdl( inf ) return tc_new( str( qtz( v ) ), hdl_tc ) def tc_file_sel( init_path='', btn_lbl='sel' ): tc = tc_new( init_path ) def hdl( inf ): dlg = wx.FileDialog( e.frame ) if dlg.ShowModal() == wx.ID_OK: tc.SetValue( dlg.GetPath() ) btn = button_new( btn_lbl, hdl ) def GetValue(): return tc.GetValue() return empty.new( locals() ) def sld_new( v, v_min, v_max, hdl=None ): sld = wx_new( wx.Slider, v, v_min, v_max ) bind( sld, hdl ) return sld def sld_float_new( v, v_min, v_max, v_step=None, hdl=None ): if v_step is None: v_step = ( v_max - v_min ) / 100 n_max = math.ceil( ( v_max - v ) / v_step ) v_max = v + v_step * n_max n_min = math.ceil( ( v - v_min ) / v_step ) v_min = v - v_step * n_min n = n_min + n_max def cnv( v_i ): return v_min + ( v_max - v_min ) * v_i / n def rcnv( v ): return int( n * ( v - v_min ) / ( v_max - v_min ) ) def hdl_( inf ): if hdl: inf.v = cnv( inf.v ) hdl( inf ) sld = sld_new( n_min, 0, n, hdl_ ) def get(): return cnv( sld.GetValue() ) def set( v ): sld.SetValue( rcnv( v ) ) obj_dic[ sld ] = empty.new( locals() ) # ! return sld def sld_float_get( sld ): return obj_dic.get( sld ).get() def sld_float_set( sld, v ): obj_dic.get( sld ).set( v ) def sld_float_tc_new( v, v_min, v_max, v_step=None, hdl=None ): def hdl_sld( inf ): tc.SetValue( str( inf.v ) ) if hdl: hdl( inf ) sld = sld_float_new( v, v_min, v_max, v_step, hdl_sld ) def hdl_tc( inf ): if inf.typeId == wx.EVT_TEXT_ENTER.typeId: s = tc.GetValue() try: v = float( s ) except: return bak = v v = max( v, v_min ) v = min( v, v_max ) sld_float_set( sld, v ) if v != bak: tc.SetValue( str( v ) ) if hdl: hdl( inf ) tc = tc_new( str( v ), hdl_tc ) return ( sld, tc ) # ! class MyApp(wx.App): def OnInit(self): e.app = self e.frame = wx_new( wx.Frame, title, parent=None ) bind( e.frame, quit_hdl, wx.EVT_CLOSE ) set_icon() init( e ) e.frame.Layout() e.frame.Fit() e.frame.FitInside() e.app.SetTopWindow( e.frame ) ( w, h ) = e.frame.GetSize() e.frame.SetMinSize( ( w, h + 10 ) ) # title bar height ? if e.on_init: e.on_init( e ) else: e.frame.Show() return 1 def set_icon( path='logo_white_square_w1000.png' ): if not e.frame: return path = exp_path( path, DIR='${IINO_DIR}/imgs' ) if not os.path.exists( path ): return bm = wx.Bitmap( path ) icon = wx.EmptyIcon() icon.CopyFromBitmap( bm ) e.frame.SetIcon( icon ) def poll_start(poll_func, sec, hz, gc): th = None if poll_func: if sec == None: if hz in ( None, 0 ): hz = 1.0 sec = 1.0 / hz def poll(): wx.CallAfter( poll_func ) th = thr.loop_new( poll, wait_tmout=sec, gc=gc ) th.start() return th def main_loop(poll_func=None, sec=None, hz=None, gc=None): th = poll_start( poll_func, sec, hz, gc ) e.app.MainLoop() if th and not gc: th.stop() def quit(): post_evt( e.frame, wx.EVT_CLOSE ) def quit_hdl(inf): if fini: fini( e ) wx.Exit() empty.to_attr( e, locals() ) # ! MyApp( 0 ) # ! return e # EOF