def _subst(self, which, wdex):
        """ Do completion.
            Params
                which   Which variant to use
                            'next' / 'prev' / '#N'
                wdex    What list to use
                            'word' / 'expr' / 'curr'
        """
        pass
        #LOG and log('which, wdex={}',(which, wdex))
        if wdex!='curr' and \
           not self._prep_sess(wdex):
            return
        if not self.sess.bids:
            return app.msg_status(_('No in-text completions'))
        shft = 1 if which == 'next' else -1 if which == 'prev' else 0
        bids_i  = int(which)                if which.isdigit()  else \
                  self.sess.bids_i + shft   if self.incr_bfr    else \
                  self.sess.bids_i
        bids_i = bids_i % len(self.sess.bids)
        sub_s = self.sess.bids[bids_i]
        add_s = sub_s[len(self.sess.src_what):]
        pass
        #LOG and log('i, sub_s, add_s={}',(bids_i, sub_s, add_s))

        if self.sess.added:
            ed.cmd(cmds.cCommand_Undo)
            pass
            #LOG and log('undo mod_ver, line={}',(ed.get_prop(app.PROP_MODIFIED_VERSION), ed.get_text_line(self.sess.row)))
        ed.delete(self.sess.src_kill_b, self.sess.row, self.sess.src_kill_e,
                  self.sess.row)
        pass
        #LOG and log('kill mod_ver, line={}',(ed.get_prop(app.PROP_MODIFIED_VERSION), ed.get_text_line(self.sess.row)))
        ed.insert(self.sess.src_what_e, self.sess.row, add_s)
        pass
        #LOG and log('insr mod_ver, line={}',(ed.get_prop(app.PROP_MODIFIED_VERSION), ed.get_text_line(self.sess.row)))
        self.sess.added = True
        if False: pass
        elif self.sess.sel_sub == 'be':
            ed.set_caret(self.sess.src_what_e + len(add_s), self.sess.row,
                         self.sess.src_what_b, self.sess.row)
        elif self.sess.sel_sub == 'eb':
            ed.set_caret(self.sess.src_what_b, self.sess.row,
                         self.sess.src_what_e + len(add_s), self.sess.row)
        else:
            ed.set_caret(self.sess.src_what_e + len(add_s), self.sess.row)
#           ed.set_caret(self.sess.src_crt,                 self.sess.row)
        self.sess.pre_mver = ed.get_prop(app.PROP_MODIFIED_VERSION)
        self.sess.pre_crt0 = ed.get_carets()[0]

        #       next_i      = (self.sess.bids_i+shft) % len(self.sess.bids)
        #       next_info   = '' if 1==len(self.sess.bids) else \
        #                     f(_('. Next #{}: "{}"'), next_i, self.sess.bids[next_i][:50])
        #       app.msg_status(f(_('In-text completion #{} ({}){}'), 1+self.sess.bids_i, len(self.sess.bids), next_info))
        app.msg_status(
            f(_('In-text completion #{} ({})'), 1 + self.sess.bids_i,
              len(self.sess.bids)))
        #       shft                = 1 if which=='next' or which[0]=='#' else -1
        self.sess.bids_i = bids_i
        self.incr_bfr = True
    def _subst(self, which, wdex):
        """ Do completion.
            Params
                which   Which variant to use
                            'next' / 'prev' / '#N'
                wdex    What list to use
                            'word' / 'expr' / 'curr'
        """
        pass;                  #LOG and log('which, wdex={}',(which, wdex))
        if wdex!='curr' and \
           not self._prep_sess(wdex): return
        if not self.sess.bids:
            return app.msg_status(_('No in-text completions'))
        shft                = 1 if which=='next' else -1 if which=='prev' else 0
        bids_i  = int(which)                if which.isdigit()  else \
                  self.sess.bids_i + shft   if self.incr_bfr    else \
                  self.sess.bids_i
        bids_i  = bids_i % len(self.sess.bids)
        sub_s   = self.sess.bids[bids_i]
        add_s   = sub_s[len(self.sess.src_what):]
        pass;                  #LOG and log('i, sub_s, add_s={}',(bids_i, sub_s, add_s))

        if self.sess.added:
            ed.cmd(cmds.cCommand_Undo)
            pass;              #LOG and log('undo mod_ver, line={}',(ed.get_prop(app.PROP_MODIFIED_VERSION), ed.get_text_line(self.sess.row)))
        ed.delete(       self.sess.src_kill_b,              self.sess.row
                        ,self.sess.src_kill_e,              self.sess.row)
        pass;                  #LOG and log('kill mod_ver, line={}',(ed.get_prop(app.PROP_MODIFIED_VERSION), ed.get_text_line(self.sess.row)))
        ed.insert(       self.sess.src_what_e,              self.sess.row,  add_s)
        pass;                  #LOG and log('insr mod_ver, line={}',(ed.get_prop(app.PROP_MODIFIED_VERSION), ed.get_text_line(self.sess.row)))
        self.sess.added     = True
        if False:pass
        elif self.sess.sel_sub=='be':
            ed.set_caret(self.sess.src_what_e+len(add_s),   self.sess.row
                        ,self.sess.src_what_b,              self.sess.row)
        elif self.sess.sel_sub=='eb':
            ed.set_caret(self.sess.src_what_b,              self.sess.row
                        ,self.sess.src_what_e+len(add_s),   self.sess.row)
        else:
            ed.set_caret(self.sess.src_what_e+len(add_s),   self.sess.row)
#           ed.set_caret(self.sess.src_crt,                 self.sess.row)
        self.sess.pre_mver  = ed.get_prop(app.PROP_MODIFIED_VERSION)
        self.sess.pre_crt0  = ed.get_carets()[0]
        
#       next_i      = (self.sess.bids_i+shft) % len(self.sess.bids)
#       next_info   = '' if 1==len(self.sess.bids) else \
#                     f(_('. Next #{}: "{}"'), next_i, self.sess.bids[next_i][:50])
#       app.msg_status(f(_('In-text completion #{} ({}){}'), 1+self.sess.bids_i, len(self.sess.bids), next_info))
        app.msg_status(f(_('In-text completion #{} ({})'),   1+self.sess.bids_i, len(self.sess.bids)))
#       shft                = 1 if which=='next' or which[0]=='#' else -1
        self.sess.bids_i    = bids_i
        self.incr_bfr       = True
 def do_code(self, aid, ag):
     m,M         = self,CfgKeysDlg
     
     lwks_n  = ag.cval('lwks')
     if lwks_n==-1:                      return [] #continue#while
     m.cmd_id  = m.fl_Is[lwks_n]
     pass;                  #LOG and log('m.fl_Is={}',(m.fl_Is))
     pass;                  #LOG and log('lwks_n,m.cmd_id={}',(lwks_n,m.cmd_id))
     if False:pass
     elif aid=='cpnm':
         cmd_nkk = m.id2nkks[m.cmd_id]
         app.app_proc(app.PROC_SET_CLIP, cmd_nkk[0])
     
     elif aid=='open':
         pass;               LOG and log('m.cmd_id={}',(m.cmd_id))
         if type(m.cmd_id)!=str:         return [] #continue#while
         plug_mdl,   \
         plug_mth    = m.cmd_id.split(',')[0:2]
         plug_mth    = 'def '+ plug_mth + '(self):'
         plug_dir    = app.app_path(app.APP_DIR_PY)+os.sep+plug_mdl
         plug_py     = plug_dir+os.sep+'__init__.py'
         plug_body   = open(plug_py, encoding='UTF-8').read()
         pass;               LOG and log('plug_mdl,plug_mth,plug_dir,plug_py={}',(plug_mdl,plug_mth,plug_dir,plug_py))
         mch         = re.search(r'from\s+\.(\w+)\s+import\s+Command', plug_body)
         if mch:
             # from .other_py import Command
             plug_py = plug_dir+os.sep+mch.group(1)+'.py'
             pass;           LOG and log('plug_py={}',(plug_py))
             plug_body=open(plug_py, encoding='UTF-8').read()
         if plug_mth not in plug_body:   return [] #continue#while
         # Open
         app.file_open(plug_py)
         # Locate
         user_opt= app.app_proc(app.PROC_GET_FINDER_PROP, '') \
                     if app.app_api_version()>='1.0.248' else \
                   app.app_proc(app.PROC_GET_FIND_OPTIONS, '')   # Deprecated
         ed.cmd(cmds.cmd_FinderAction, chr(1).join([]
             +['findnext']
             +[plug_mth]
             +['']
             +['fa']
         ))
         if app.app_api_version()>='1.0.248':
             app.app_proc(app.PROC_SET_FINDER_PROP, user_opt)
         else:
             app.app_proc(app.PROC_SET_FIND_OPTIONS, user_opt)   # Deprecated
         return None #break#while
     return []
示例#4
0
 def do_code(self, aid, ag, data=''):
     m,M         = self,self.__class__
     
     lwks_n  = ag.cval('lwks')
     if lwks_n==-1:                      return [] #continue#while
     m.cmd_id  = m.fl_Is[lwks_n]
     pass;                  #LOG and log('m.fl_Is={}',(m.fl_Is))
     pass;                  #LOG and log('lwks_n,m.cmd_id={}',(lwks_n,m.cmd_id))
     if False:pass
     elif aid=='cpnm':
         cmd_nkk = m.id2nkks[m.cmd_id]
         app.app_proc(app.PROC_SET_CLIP, cmd_nkk[0])
     
     elif aid=='open':
         pass;               LOG and log('m.cmd_id={}',(m.cmd_id))
         if type(m.cmd_id)!=str:         return [] #continue#while
         plug_mdl,   \
         plug_mth    = m.cmd_id.split(',')[0:2]
         plug_mth    = 'def '+ plug_mth + '(self):'
         plug_dir    = app.app_path(app.APP_DIR_PY)+os.sep+plug_mdl
         plug_py     = plug_dir+os.sep+'__init__.py'
         plug_body   = open(plug_py, encoding='UTF-8').read()
         pass;               LOG and log('plug_mdl,plug_mth,plug_dir,plug_py={}',(plug_mdl,plug_mth,plug_dir,plug_py))
         mch         = re.search(r'from\s+\.(\w+)\s+import\s+Command', plug_body)
         if mch:
             # from .other_py import Command
             plug_py = plug_dir+os.sep+mch.group(1)+'.py'
             pass;           LOG and log('plug_py={}',(plug_py))
             plug_body=open(plug_py, encoding='UTF-8').read()
         if plug_mth not in plug_body:   return [] #continue#while
         # Open
         app.file_open(plug_py)
         # Locate
         user_opt= app.app_proc(app.PROC_GET_FINDER_PROP, '') \
                     if app.app_api_version()>='1.0.248' else \
                   app.app_proc(app.PROC_GET_FIND_OPTIONS, '')   # Deprecated
         ed.cmd(cmds.cmd_FinderAction, chr(1).join([]
             +['findnext']
             +[plug_mth]
             +['']
             +['fa']
         ))
         if app.app_api_version()>='1.0.248':
             app.app_proc(app.PROC_SET_FINDER_PROP, user_opt)
         else:
             app.app_proc(app.PROC_SET_FIND_OPTIONS, user_opt)   # Deprecated
         return None #break#while
     return []
示例#5
0
    def do_setv(self, aid, ag, data):
        M,m = self.__class__,self
        pass;                  #LOG and log('aid,m.cur_op={}',(aid,m.cur_op))
        if not m.cur_op:   return []
        #m.col_ws= [ci['wd'] for ci in m.ag.cattr('lvls', 'cols')]

        cur_val = data

        trg     = 'lexer '+m.lexr+'.json' if m.for_ulf=='l' else 'user.join'
        key4v   = m.for_ulf+'val'
        op      = m.cur_op
        oi      = m.opts_full[op]
        frm     = oi['frm']

        dval    = oi.get( 'def')
        uval    = oi.get('uval')
        lval    = oi.get('lval')
        fval    = oi.get('fval')
        ulfvl   = oi.get(key4v ) #fval if m.for_ulf=='f' else lval if m.for_ulf=='l' else uval
        jval    = oi['jlvl']    if m.for_ulf=='l' else \
                  oi['juvl']    if m.for_ulf=='u' else \
                  oi['jfvl']

        # Get new value
        newv    = None
        erpt_s  = ''
        if False:pass

        elif aid=='setd'  and  m.for_ulf=='f'  and  op in apx.OPT2PROP:
            # Remove from file - set over def/user/lex val
            newv    = oi.get('lval', oi.get('uval', oi.get('def')))
            if newv==ulfvl:
                #m.stbr_act(M.STBR_MSG, _('No need changes'))
                return []
            erpt_s  = 'reset-f'
            m.ed.set_prop(apx.OPT2PROP[op], newv)

        elif aid=='setd'  and  ulfvl is not None  and  m.for_ulf!='f':
            # Remove from user/lexer
            newv= None

        elif aid=='setv':                   # Add/Set opt for user/lexer/file
            # Enter from edit. Need parse some string
            #newv    = m.ag.cval('eded')
            newv    = cur_val
            try:
                newv    =   int(newv)   if frm=='int'   else \
                          float(newv)   if frm=='float' else \
                                newv
            except Exception as ex:
                app.msg_box(f(_('Incorrect value. It\'s needed in format: {}'), frm)
                           , app.MB_OK+app.MB_ICONWARNING)
                return d(form=d(fid='eded'))
            if frm=='#rgb' or frm=='#rgb-e' and newv:       # Testing new val
                try:
                    apx.html_color_to_int(newv)
                except Exception as ex:
                    app.msg_box(f(_('Incorrect value. It\'s needed in format: {}'), '#RGB or #RRGGBB')
                               , app.MB_OK+app.MB_ICONWARNING)
                    return d(form=d(fid='eded'))


        ### Use new value to change env
        if newv is not None and newv==ulfvl:
            #m.stbr_act(M.STBR_MSG, _('No need changes'))
            return []

        if m.for_ulf=='f' and newv is not None and op in apx.OPT2PROP:
            # Change for file
            erpt_s  = 'set-f'
            ed.set_prop(apx.OPT2PROP[op], newv)

        if m.for_ulf!='f':
            # Change target file
            pass;              #LOG and log('?? do_erpt',())
            erpt_s  =('reset-u' if newv  is None and m.for_ulf=='u' else
                      'reset-l' if newv  is None and m.for_ulf=='l' else
                      'add-u'   if ulfvl is None and m.for_ulf=='u' else
                      'add-l'   if ulfvl is None and m.for_ulf=='l' else
                      'set-u'   if                   m.for_ulf=='u' else
                      'set-l'   if                   m.for_ulf=='l' else '')
            pass;              #LOG and log('?? set_opt',())
            apx.set_opt(op
                       ,newv
                       ,apx.CONFIG_LEV_LEX  if m.for_ulf=='l' else apx.CONFIG_LEV_USER
                       ,ed_cfg  =None
                       ,lexer   =m.lexr     if m.for_ulf=='l' else None
                       ,user_json=m.how.get('stor_json', 'user.json')
                       )

            if not m.apply_one:
                pass;          #LOG and log('?? OpsReloadAndApply',())
                ed.cmd(cmds.cmd_OpsReloadAndApply)
            else:
                m.apply_need    = True

        # Use new value to change dlg data
        pass;                  #LOG and log('?? oi={}',(oi))
        pass;                  #LOG and log('?? m.opts_full={}',pf(m.opts_full))
        if False:pass
        elif aid=='setd':
            oi.pop(key4v, None)     if m.for_ulf!='f' else 0
        else:
            pass;              #LOG and log('key4v, newv={}',(key4v, newv))
            oi[key4v] = newv
        pass;                  #LOG and log('oi={}',(oi))
        upd_cald_vals(m.opts_full)
        pass;                  #LOG and log('oi={}',(oi))

        jnewv   = oi['jlvl']   if m.for_ulf=='l' else oi['juvl']    if m.for_ulf=='u' else oi['jfvl']
        #m.do_erpt(erpt_s, jnewv, jval)
        pass;                  #LOG and log('ok oi={}',(oi))
        pass;                  #LOG and log('ok m.opts_full={}',pf(m.opts_full))

        pass;                  #LOG and log('?? get_cnts',())

        if m.for_ulf!='f' and m.auto4file and op in apx.OPT2PROP:
            # Change FILE to over  (("over" - override?))
            newv    = oi.get('lval', oi.get('uval', oi.get('def')))
            if newv!=oi.get('fval'):
                erpt_s      = 'reset-f'
                m.ed.set_prop(apx.OPT2PROP[op], newv)
                oi['fval']  = newv
                jval        = oi['jfvl']
                upd_cald_vals(m.opts_full)
                jnewv       = oi['jfvl']
                #m.do_erpt('auset-f', jnewv, jval)

        pass;                  #LOG and log('m.get_vals(lvls-cur)={}',(m.get_vals('lvls-cur')))
示例#6
0
 def add_indented_line_below(self):
     ed.cmd(cmds.cCommand_KeyEnd)
     ed.cmd(cmds.cCommand_KeyEnter)
示例#7
0
 def add_indented_line_above(self):
     ed.cmd(cmds.cCommand_KeyUp)
     ed.cmd(cmds.cCommand_KeyEnd)
     ed.cmd(cmds.cCommand_KeyEnter)
示例#8
0
    def dlg_config(self):
        ''' Show dlg for change macros list.
        '''
        if app.app_api_version()<FROM_API_VERSION:  return app.msg_status('Need update CudaText')
        keys_json   = app.app_path(app.APP_DIR_SETTINGS)+os.sep+'keys.json'
        keys        = apx._json_loads(open(keys_json).read()) if os.path.exists(keys_json) else {}
        GAP     = 5
        
        ids     = [mcr['id'] for mcr in self.macros]
        mcr_ind = ids.index(self.last_mcr_id) if self.last_mcr_id in ids else -1
        pass;                   LOG and log('self.last_mcr_id, mcr_ind={}',(self.last_mcr_id,mcr_ind))
        times   = 1
        waits   = 5
        chngs   = '0'
        endln   = '0'
        while True:
            (WD_LST
            ,HT_LST)= (self.dlg_prs.get('w_list', 300)
                      ,self.dlg_prs.get('h_list', 500))
            (WD_ACTS
            ,HT_ACTS)=(self.dlg_prs.get('w_acts', 300)
                      ,self.dlg_prs.get('h_acts', 500))
            (WD_BTN
            ,HT_BTN)= (self.dlg_prs.get('w_btn', 150), 24)
            l_btn   = GAP+WD_LST+GAP
            
            vw_acts = (WD_ACTS>0)
            WD_ACTS = max(0, WD_ACTS)
            rec_on  = ed.get_prop(app.PROP_MACRO_REC)
            lmcrs   = len(self.macros)
            pass;               LOG and log('mcr_ind,vw_acts,rec_on={}',(mcr_ind,vw_acts,rec_on))

            nmkys   = []
            for mcr in self.macros:
                mcr_cid = 'cuda_macros,run,{}'.format(mcr['id'])
                mcr_keys= keys.get(mcr_cid, {})
                kys     = '/'.join([' * '.join(mcr_keys.get('s1', []))
                                   ,' * '.join(mcr_keys.get('s2', []))
                                   ]).strip('/')
                nmkys  += [mcr['nm'] + (' ['+kys+']' if kys else '')]

            mcr_acts= ''
            if vw_acts and mcr_ind in range(lmcrs):
                mcr     = self.macros[mcr_ind]
                mcr_acts= '\t'.join(['# '+nmkys[mcr_ind]] + mcr['evl'])

            ans = app.dlg_custom('Macros'   ,GAP+WD_LST+GAP+WD_BTN+GAP+WD_ACTS+GAP,GAP+HT_LST+GAP, '\n'.join([]
            +[C1.join(['type=listbox'   ,POS_FMT(l=GAP,    t=GAP,           r=GAP+WD_LST,   b=GAP+HT_LST)
                      ,'items=' +'\t'.join(nmkys)
                      ,'val='   +str(mcr_ind)  # start sel
                      ,'en='    +str(0 if rec_on else 1)        # enabled
                      ] # i=0
             )]
            +([C1.join(['type=button'    ,POS_FMT(l=l_btn,  t=GAP*1+HT_BTN*0,    r=l_btn+WD_BTN, b=0)
                      ,'cap=&View actions...'
                      ,'props=' +str(0 if    rec_on or 0==lmcrs else 1)    # default
                      ,'en='    +str(0 if    rec_on or 0==lmcrs else 1)    # enabled
                      ] # i=1
             )] if vw_acts else [])
            +[C1.join(['type=button'    ,POS_FMT(l=l_btn,  t=GAP*2+HT_BTN*1,    r=l_btn+WD_BTN, b=0)
                      ,'cap=Hot&keys...'
                      ,'en='    +str(0 if    rec_on or 0==lmcrs else 1)     # enabled
                      ] # i=2 if vw_acts else i=1
             )]
            +[C1.join(['type=button'    ,POS_FMT(l=l_btn,  t=GAP*3+HT_BTN*2,    r=l_btn+WD_BTN, b=0)
                      ,'cap=Re&name...'
                      ,'en='    +str(0 if    rec_on or 0==lmcrs else 1)     # enabled
                      ] # i=3 if vw_acts else i=2
             )]
            +[C1.join(['type=button'    ,POS_FMT(l=l_btn,  t=GAP*4+HT_BTN*3,    r=l_btn+WD_BTN, b=0)
                      ,'cap=&Delete...'
                      ,'en='    +str(0 if    rec_on or 0==lmcrs else 1)     # enabled
                      ] # i=4 if vw_acts else i=3
             )]

            +[C1.join(['type=button'    ,POS_FMT(l=l_btn,                   t=GAP*6+HT_BTN*5,    r=l_btn+WD_BTN, b=0)
                      ,'cap=&Run!'
                      ,'props=' +str(1 if not vw_acts and not rec_on else 0)     # default
                      ,'en='    +str(0 if    rec_on or 0==lmcrs else 1)     # enabled
                      ] # i=5 if vw_acts else i=4
             )]
            +[C1.join(['type=label'     ,POS_FMT(l=l_btn,                   t=GAP*7+HT_BTN*6+3, r=l_btn+int(WD_BTN/3),b=0)
                      ,'cap=&Times'
                      ] # i=6 if vw_acts else i=5
             )]
            +[C1.join(['type=spinedit'  ,POS_FMT(l=l_btn+int(WD_BTN/3)+GAP, t=GAP*7+HT_BTN*6,   r=l_btn+WD_BTN, b=0)
                      ,'val='   +str(times)
                      ,'props=0,{},1'.format(self.dlg_prs.get('times',  1000))
                      ,'en='    +str(0 if    rec_on else 1)     # enabled
                      ] # i=7 if vw_acts else i=6
             )]
            +[C1.join(['type=label'     ,POS_FMT(l=l_btn,                   t=GAP*8+HT_BTN*7+3, r=l_btn+int(WD_BTN/3),b=0)
                      ,'cap=&Wait'
                      ] # i=8 if vw_acts else i=7
             )]
            +[C1.join(['type=spinedit'  ,POS_FMT(l=l_btn+int(WD_BTN/3)+GAP, t=GAP*8+HT_BTN*7,   r=l_btn+WD_BTN-40, b=0)
                      ,'val='   +str(waits)
                      ,'props=1,3600,1'
                      ,'en='    +str(0 if    rec_on else 1)     # enabled
                      ] # i=9 if vw_acts else i=8
             )]
            +[C1.join(['type=label'     ,POS_FMT(l=l_btn+WD_BTN-40+GAP,     t=GAP*8+HT_BTN*7+3, r=l_btn+WD_BTN,b=0)
                      ,'cap=sec'
                      ] # i=10 if vw_acts else i=9
             )]
            +[C1.join(['type=check'     ,POS_FMT(l=l_btn,                   t=GAP*9+HT_BTN*8, r=l_btn+WD_BTN,b=0)
                      ,'cap=While text c&hanges'
                      ,'val='   +chngs
                      ] # i=11 if vw_acts else i=10
             )]
            +[C1.join(['type=check'     ,POS_FMT(l=l_btn,                   t=GAP*10+HT_BTN*9, r=l_btn+WD_BTN,b=0)
                      ,'cap=Until c&aret on last line'
                      ,'val='   +endln
                      ] # i=12 if vw_acts else i=11
             )]

            +[C1.join(['type=button'    ,POS_FMT(l=l_btn,  t=GAP*12+HT_BTN*11,    r=l_btn+WD_BTN, b=0)
                      ,'cap={}'.format('&Stop record' if rec_on else '&Start record')
                      ,'props=' +str(1 if    rec_on or 0==lmcrs else 0)     # default
                      ] # i=13 if vw_acts else i=12
             )]
            +[C1.join(['type=button'    ,POS_FMT(l=l_btn,  t=GAP*13+HT_BTN*12,    r=l_btn+WD_BTN, b=0)
                      ,'cap=Canc&el record'
                      ,'en='    +str(1 if    rec_on else 0)     # enabled
                      ] # i=14 if vw_acts else i=13
             )]

            +[C1.join(['type=button'    ,POS_FMT(l=l_btn,  t=    HT_LST-HT_BTN*2, r=l_btn+WD_BTN, b=0)
                      ,'cap=C&ustom...'
                      ,'en='    +str(0 if    rec_on else 1)     # enabled
                      ] # i=15 if vw_acts else i=14
             )]
            +[C1.join(['type=button'    ,POS_FMT(l=l_btn,  t=GAP+HT_LST-HT_BTN*1, r=l_btn+WD_BTN, b=0)
                      ,'cap=&Close'
                      ] # i=16 if vw_acts else i=15
             )]
            +([C1.join(['type=memo'      ,POS_FMT(l=GAP+WD_LST+GAP+WD_BTN+GAP,   t=GAP,  r=GAP+WD_LST+GAP+WD_BTN+GAP+WD_ACTS, b=GAP+HT_ACTS)
                      ,'val='+mcr_acts
                      ,'props=1,1,1'    # ro,mono,border
                      ] # i=17
             )] if vw_acts else [])
            ), apx.icase(    vw_acts and not rec_on, 0  # View
                        ,not vw_acts and not rec_on, 0  # View
                        ,    vw_acts and     rec_on, 11
                        ,not vw_acts and     rec_on, 10
                        ))    # start focus
            pass;               LOG and log('ans={}',ans)
            if ans is None:  break #while
            (ans_i
            ,vals)  = ans
            ans_s   = apx.icase(False,''
                       ,vw_acts and ans_i==1, 'view'
                       ,vw_acts and ans_i==2, 'hotkeys' ,not vw_acts and ans_i==1, 'hotkeys'
                       ,vw_acts and ans_i==3, 'rename'  ,not vw_acts and ans_i==2, 'rename' 
                       ,vw_acts and ans_i==4, 'delete'  ,not vw_acts and ans_i==3, 'delete' 
                       ,vw_acts and ans_i==5, 'run'     ,not vw_acts and ans_i==4, 'run'    
                       ,vw_acts and ans_i==12,'rec'     ,not vw_acts and ans_i==7, 'rec'    
                       ,vw_acts and ans_i==14,'cancel'  ,not vw_acts and ans_i==13,'cancel' 
                       ,vw_acts and ans_i==15,'custom'  ,not vw_acts and ans_i==14,'custom' 
                       ,vw_acts and ans_i==16,'close'   ,not vw_acts and ans_i==15,'close'  
                       ,'?')
            mcr_ind = int(vals.splitlines()[0])
            times   = int(vals.splitlines()[ 7 if vw_acts else  6])
            waits   = int(vals.splitlines()[ 9 if vw_acts else  8])
            chngs   =     vals.splitlines()[11 if vw_acts else 10]
            endln   =     vals.splitlines()[12 if vw_acts else 11]
            pass;               LOG and log('mcr_ind,times,waits,chngs,endln={}',(mcr_ind,times,waits,chngs,endln))

            if 0!=lmcrs and mcr_ind in range(lmcrs):
                mcr     = self.macros[mcr_ind]
                self.last_mcr_id = mcr['id']
            
            if ans_s=='close':  break #while
            if ans_s=='custom': #Custom
                custs   = app.dlg_input_ex(5, 'Custom dialog Macros'
                    , 'Height of macro list (min 450)'          , str(self.dlg_prs.get('h_list', 400))
                    , 'Width of macro list (min 200)'           , str(self.dlg_prs.get('w_list', 500))
                    , 'Width of action list (min 200, <=0-hide)', str(self.dlg_prs.get('w_acts', 500))
                    , 'Width of buttons (min 150)'              , str(self.dlg_prs.get('w_btn',  150))
                    , 'Max run times (min 100)'                 , str(self.dlg_prs.get('times',  1000))
                    )
                if custs is not None:
                    self.dlg_prs['h_list']  = max(450, int(custs[0]));  self.dlg_prs['h_acts'] = self.dlg_prs['h_list']
                    self.dlg_prs['w_list']  = max(200, int(custs[1]))
                    self.dlg_prs['w_acts']  = max(200, int(custs[2])) if int(custs[2])>0 else int(custs[2])
                    self.dlg_prs['w_btn']   = max(150, int(custs[3]))
                    self.dlg_prs['times']   = max(100, int(custs[4]))
                    open(MACROS_JSON, 'w').write(json.dumps({'ver':JSON_FORMAT_VER, 'list':self.macros, 'dlg_prs':self.dlg_prs}, indent=4))
                continue #while
            
            if mcr_ind not in range(lmcrs):
                app.msg_box('Select macro', app.MB_OK)
                continue #while
            
            what    = ''
            changed = False
            if False:pass
                
            elif ans_s=='view': #View
                continue #while

            elif ans_s=='rename': #Rename
                mcr_nm      = app.dlg_input('New name for: {}'.format(nmkys[mcr_ind])
                                           ,mcr['nm'])
                if mcr_nm is None or mcr_nm==mcr['nm']:     continue #while
                while mcr_nm in [mcr['nm'] for mcr in self.macros]:
                    app.msg_box('Select other name.\nMacro names now are:\n\n'+'\n'.join(nmkys), app.MB_OK)
                    mcr_nm  = app.dlg_input('New name for: {}'.format(nmkys[mcr_ind])
                                           ,mcr_nm)
                    if mcr_nm is None or mcr_nm==mcr['nm']: break #while mcr_nm
                if mcr_nm is None or mcr_nm==mcr['nm']:     continue #while
                what        = 'rename'
                mcr['nm']   = mcr_nm
                changed = True
                
            elif ans_s=='delete': #Del
                if app.msg_box( 'Delete macro\n    {}'.format(nmkys[mcr_ind])
                              , app.MB_YESNO)!=app.ID_YES:  continue #while
                what    = 'delete:'+str(mcr['id'])
                del self.macros[mcr_ind]
                mcr_ind = min(mcr_ind, len(self.macros)-1)
                changed = True
                
            elif ans_s=='hotkeys': #Hotkeys
                app.dlg_hotkeys('cuda_macros,run,'+str(mcr['id']))
                keys    = apx._json_loads(open(keys_json).read()) if os.path.exists(keys_json) else {}
                changed = True

            elif ans_s=='run': #Run
                if (times==0 
                and waits==0
                and chngs=='0'
                and endln=='0'):
                    app.msg_box('Select stop condition', app.MB_OK)
                    continue
                self.run(mcr['id'], max(0, times), max(0, waits), chngs=='1', endln=='1')
                return

            elif ans_s=='rec'    and not rec_on: #Start record
                return ed.cmd(cmds.cmd_MacroStart)
            elif ans_s=='rec'    and     rec_on: #Stop record
                self.need_dlg = True
                return ed.cmd(cmds.cmd_MacroStop)       # Return for clear rec-mode in StatusBar, will recall from on_macro
            elif ans_s=='cancel' and     rec_on: #Cancel record
                return ed.cmd(cmds.cmd_MacroCancel)     # Return for clear rec-mode in StatusBar
                
            if changed:
                self._do_acts(what)
示例#9
0
    def dlg_config(self):
        ''' Show dlg for change macros list.
        '''
        if app.app_api_version()<FROM_API_VERSION:  return app.msg_status(_('Need update CudaText'))
        keys_json   = app.app_path(app.APP_DIR_SETTINGS)+os.sep+'keys.json'
        keys        = apx._json_loads(open(keys_json).read()) if os.path.exists(keys_json) else {}
        
        ids     = [mcr['id'] for mcr in self.macros]
        mcr_ind = ids.index(self.last_mcr_id) if self.last_mcr_id in ids else -1
        pass;                   LOG and log('self.last_mcr_id, mcr_ind={}',(self.last_mcr_id,mcr_ind))
        times   = 1
        waits   = 5
        chngs   = '0'
        endln   = '0'
        while True:
            WD_LST, \
            HT_LST  = (self.dlg_prs.get('w_list', 300)
                      ,self.dlg_prs.get('h_list', 500))
            WD_ACTS,\
            HT_ACTS = (self.dlg_prs.get('w_acts', 300)
                      ,self.dlg_prs.get('h_acts', 500))
            WD_BTN, \
            HT_BTN  = (self.dlg_prs.get('w_btn', 150), 24)
            WD_BTN_3= int(WD_BTN/3)
            l_btn   = GAP+WD_LST+GAP
            l_acts  = GAP+WD_LST+GAP+WD_BTN+GAP
            
            vw_acts = (WD_ACTS>0)
            WD_ACTS = max(0, WD_ACTS)
            rec_on  = ed.get_prop(app.PROP_MACRO_REC)
            lmcrs   = len(self.macros)
            pass;               LOG and log('mcr_ind,vw_acts,rec_on={}',(mcr_ind,vw_acts,rec_on))

            nmkys   = []
            for mcr in self.macros:
                mcr_cid = 'cuda_macros,run,{}'.format(mcr['id'])
                mcr_keys= keys.get(mcr_cid, {})
                kys     = '/'.join([' * '.join(mcr_keys.get('s1', []))
                                   ,' * '.join(mcr_keys.get('s2', []))
                                   ]).strip('/')
                nmkys  += [mcr['nm'] + (' ['+kys+']' if kys else '')]

            mcr_acts= ['']
#           mcr_acts= ''
            if vw_acts and mcr_ind in range(lmcrs):
                mcr     = self.macros[mcr_ind]
                mcr_acts=           ['# '+nmkys[mcr_ind]] + mcr['evl']
#               mcr_acts= '\t'.join(['# '+nmkys[mcr_ind]] + mcr['evl'])

            def_stst    = '1' if                     rec_on or 0==lmcrs else '0'
            n_edable    = '0' if                     rec_on or 0==lmcrs else '1'
            n_vwable    = '1' if not vw_acts and not rec_on else '0'
            only_rec_off= '0' if                     rec_on else '1'
            only_rec_on = '1' if                     rec_on else '0'
            tims_props  = '0,{},1'.format(self.dlg_prs.get('times',  1000))
            stst_cap    = _('&Stop record') if       rec_on else _('&Start record')
            cnts        = ([]
 +[dict(cid='mrcs'   ,tp='lbx'  ,t=GAP  ,h=HT_LST       ,l=GAP                  ,w=WD_LST   ,items=nmkys                            ,en=only_rec_off    )]
 +(                                                                                                     
  [dict(cid='view'   ,tp='bt'   ,t=GAP* 1+HT_BTN* 0     ,l=l_btn                ,w=WD_BTN   ,cap=_('&View actions') ,props=n_edable,en=n_edable         )]  # default
  if vw_acts else [])                                                                                     
 +[dict(cid='keys'   ,tp='bt'   ,t=GAP* 2+HT_BTN* 1     ,l=l_btn                ,w=WD_BTN   ,cap=_('Hot&keys...')                   ,en=n_edable        )]
 +[dict(cid='renm'   ,tp='bt'   ,t=GAP* 3+HT_BTN* 2     ,l=l_btn                ,w=WD_BTN   ,cap=_('Re&name...')                    ,en=n_edable        )]
 +[dict(cid='del'    ,tp='bt'   ,t=GAP* 4+HT_BTN* 3     ,l=l_btn                ,w=WD_BTN   ,cap=_('&Delete...')                    ,en=n_edable        )]
 +[dict(cid='run'    ,tp='bt'   ,t=GAP* 6+HT_BTN* 5     ,l=l_btn                ,w=WD_BTN   ,cap=_('&Run!')         ,props=n_vwable ,en=n_edable        )]  # default
 +[dict(              tp='lb'   ,tid='times'            ,l=l_btn                ,w=WD_BTN_3 ,cap=_('&Times')                                            )]
 +[dict(cid='times'  ,tp='sp-ed',t=GAP* 7+HT_BTN* 6     ,l=l_btn+WD_BTN_3+GAP   ,r=l_btn+WD_BTN                     ,props=tims_props,en=only_rec_off   )]  # min,max,step
 +[dict(              tp='lb'   ,tid='waits'            ,l=l_btn                ,w=WD_BTN_3 ,cap=_('&Wait')                                             )]
 +[dict(cid='waits'  ,tp='sp-ed',t=GAP* 8+HT_BTN* 7     ,l=l_btn+WD_BTN_3+GAP   ,r=l_btn+WD_BTN-40                  ,props='1,3600,1',en=only_rec_off   )]  # min,max,step
 +[dict(              tp='lb'   ,tid='waits'            ,l=l_btn+WD_BTN-40+GAP  ,w=WD_BTN   ,cap=_('sec')                                               )]
 +[dict(cid='chngs'  ,tp='ch'   ,t=GAP* 9+HT_BTN* 8     ,l=l_btn                ,w=WD_BTN   ,cap=_('While text c&hanges')                               )]
 +[dict(cid='endln'  ,tp='ch'   ,t=GAP*10+HT_BTN* 9     ,l=l_btn                ,w=WD_BTN   ,cap=_('Until c&aret on last line')                         )]
 +[dict(cid='stst'   ,tp='bt'   ,t=GAP*12+HT_BTN*11     ,l=l_btn                ,w=WD_BTN   ,cap=stst_cap           ,props=def_stst                     )]
 +[dict(cid='canc'   ,tp='bt'   ,t=GAP*13+HT_BTN*12     ,l=l_btn                ,w=WD_BTN   ,cap=_('Canc&el record')                ,en=only_rec_on     )]
 +[dict(cid='adju'   ,tp='bt'   ,t=    HT_LST-HT_BTN*2  ,l=l_btn                ,w=WD_BTN   ,cap=_('Ad&just...')                    ,en=only_rec_off    )]
 +[dict(cid='-'      ,tp='bt'   ,t=GAP+HT_LST-HT_BTN*1  ,l=l_btn                ,w=WD_BTN   ,cap=_('Close')                                             )]
 +(
  [dict(cid='acts'   ,tp='me'   ,t=GAP  ,h=HT_ACTS      ,l=l_acts               ,w=WD_ACTS                          ,props='1,1,1'                      )]  # ro,mono,border
  if vw_acts else [])
                    )
            vals    = dict( mrcs=mcr_ind
                           ,times=times
                           ,waits=waits
                           ,chngs=chngs
                           ,endln=endln
                        )
            if vw_acts: vals.update(
                      dict( acts=mcr_acts
                        ))
            btn,    \
            vals,   \
            chds    = dlg_wrapper(_('Macros'), GAP+WD_LST+GAP+WD_BTN+GAP+WD_ACTS+GAP,GAP+HT_LST+GAP, cnts, vals, focus_cid='mrcs')
            if btn is None or btn=='-': return
            mcr_ind = vals['mrcs']
            times   = vals['times']
            waits   = vals['waits']
            chngs   = vals['chngs']
            endln   = vals['endln']
            pass;               LOG and log('mcr_ind,times,waits,chngs,endln={}',(mcr_ind,times,waits,chngs,endln))

            if 0!=lmcrs and mcr_ind in range(lmcrs):
                mcr     = self.macros[mcr_ind]
                self.last_mcr_id = mcr['id']
            
#           if ans_s=='close':  break #while
            if btn=='adju': #ans_s=='custom': #Custom
                custs   = app.dlg_input_ex(5, _('Custom dialog Macros')
                    , _('Height of macro list (min 450)')          , str(self.dlg_prs.get('h_list', 400))
                    , _('Width of macro list (min 200)')           , str(self.dlg_prs.get('w_list', 500))
                    , _('Width of action list (min 200, <=0-hide)'), str(self.dlg_prs.get('w_acts', 500))
                    , _('Width of buttons (min 150)')              , str(self.dlg_prs.get('w_btn',  150))
                    , _('Max run times (min 100)')                 , str(self.dlg_prs.get('times',  1000))
                    )
                if custs is not None:
                    self.dlg_prs['h_list']  = max(450, int(custs[0]));  self.dlg_prs['h_acts'] = self.dlg_prs['h_list']
                    self.dlg_prs['w_list']  = max(200, int(custs[1]))
                    self.dlg_prs['w_acts']  = max(200, int(custs[2])) if int(custs[2])>0 else int(custs[2])
                    self.dlg_prs['w_btn']   = max(150, int(custs[3]))
                    self.dlg_prs['times']   = max(100, int(custs[4]))
                    open(MACROS_JSON, 'w').write(json.dumps({'ver':JSON_FORMAT_VER, 'list':self.macros, 'dlg_prs':self.dlg_prs}, indent=4))
                continue #while
            
            if mcr_ind not in range(lmcrs):
                app.msg_box(_('Select macro'), app.MB_OK)
                continue #while
            
            what    = ''
            changed = False
            if False:pass
                
            elif btn=='view': #ans_s=='view': #View
                continue #while

            elif btn=='renm': #ans_s=='rename': #Rename
                mcr_nm      = app.dlg_input(_('New name for: {}').format(nmkys[mcr_ind])
                                           ,mcr['nm'])
                if mcr_nm is None or mcr_nm==mcr['nm']:     continue #while
                while mcr_nm in [mcr['nm'] for mcr in self.macros]:
                    app.msg_box(_('Select other name.\nMacro names now are:\n\n')+'\n'.join(nmkys), app.MB_OK)
                    mcr_nm  = app.dlg_input(_('New name for: {}').format(nmkys[mcr_ind])
                                           ,mcr_nm)
                    if mcr_nm is None or mcr_nm==mcr['nm']: break #while mcr_nm
                if mcr_nm is None or mcr_nm==mcr['nm']:     continue #while
                what        = 'rename'
                mcr['nm']   = mcr_nm
                changed = True
                
            elif btn=='del': #ans_s=='delete': #Del
                if app.msg_box( _('Delete macro\n    {}').format(nmkys[mcr_ind])
                              , app.MB_YESNO)!=app.ID_YES:  continue #while
                what    = 'delete:'+str(mcr['id'])
                del self.macros[mcr_ind]
                mcr_ind = min(mcr_ind, len(self.macros)-1)
                changed = True
                
            elif btn=='keys': #ans_s=='hotkeys': #Hotkeys
                app.dlg_hotkeys('cuda_macros,run,'+str(mcr['id']))
                keys    = apx._json_loads(open(keys_json).read()) if os.path.exists(keys_json) else {}
                changed = True

            elif btn=='run': #ans_s=='run': #Run
                if (times==0 
                and waits==0
                and chngs=='0'
                and endln=='0'):
                    app.msg_box(_('Select stop condition'), app.MB_OK)
                    continue
                self.run(mcr['id'], max(0, times), max(0, waits), chngs=='1', endln=='1')
                return

            elif btn=='stst'     and not rec_on: #Start record
#           elif ans_s=='rec'    and not rec_on: #Start record
                return ed.cmd(cmds.cmd_MacroStart)
            elif btn=='stst'     and     rec_on: #Stop record
#           elif ans_s=='rec'    and     rec_on: #Stop record
                self.need_dlg = True
                return ed.cmd(cmds.cmd_MacroStop)       # Return for clear rec-mode in StatusBar, will recall from on_macro
            elif btn=='canc'     and     rec_on: #Cancel record
#           elif ans_s=='cancel' and     rec_on: #Cancel record
                return ed.cmd(cmds.cmd_MacroCancel)     # Return for clear rec-mode in StatusBar
                
            if changed:
                self._do_acts(what)
示例#10
0
    def dlg_config(self):
        ''' Show dlg for change macros list.
        '''
        if app.app_api_version() < FROM_API_VERSION:
            return app.msg_status('Need update CudaText')
        keys_json = app.app_path(app.APP_DIR_SETTINGS) + os.sep + 'keys.json'
        keys = apx._json_loads(
            open(keys_json).read()) if os.path.exists(keys_json) else {}
        GAP = 5

        ids = [mcr['id'] for mcr in self.macros]
        mcr_ind = ids.index(
            self.last_mcr_id) if self.last_mcr_id in ids else -1
        pass
        LOG and log('self.last_mcr_id, mcr_ind={}',
                    (self.last_mcr_id, mcr_ind))
        times = 1
        waits = 5
        chngs = '0'
        endln = '0'
        while True:
            (WD_LST, HT_LST) = (self.dlg_prs.get('w_list', 300),
                                self.dlg_prs.get('h_list', 500))
            (WD_ACTS, HT_ACTS) = (self.dlg_prs.get('w_acts', 300),
                                  self.dlg_prs.get('h_acts', 500))
            (WD_BTN, HT_BTN) = (self.dlg_prs.get('w_btn', 150), 24)
            l_btn = GAP + WD_LST + GAP

            vw_acts = (WD_ACTS > 0)
            WD_ACTS = max(0, WD_ACTS)
            rec_on = ed.get_prop(app.PROP_MACRO_REC)
            lmcrs = len(self.macros)
            pass
            LOG and log('mcr_ind,vw_acts,rec_on={}',
                        (mcr_ind, vw_acts, rec_on))

            nmkys = []
            for mcr in self.macros:
                mcr_cid = 'cuda_macros,run,{}'.format(mcr['id'])
                mcr_keys = keys.get(mcr_cid, {})
                kys = '/'.join([
                    ' * '.join(mcr_keys.get('s1', [])),
                    ' * '.join(mcr_keys.get('s2', []))
                ]).strip('/')
                nmkys += [mcr['nm'] + (' [' + kys + ']' if kys else '')]

            mcr_acts = ''
            if vw_acts and mcr_ind in range(lmcrs):
                mcr = self.macros[mcr_ind]
                mcr_acts = '\t'.join(['# ' + nmkys[mcr_ind]] + mcr['evl'])

            ans = app.dlg_custom(
                'Macros',
                GAP + WD_LST + GAP + WD_BTN + GAP + WD_ACTS + GAP,
                GAP + HT_LST + GAP,
                '\n'.join([] + [
                    C1.join([
                        'type=listbox',
                        POS_FMT(l=GAP, t=GAP, r=GAP + WD_LST, b=GAP + HT_LST),
                        'items=' + '\t'.join(nmkys),
                        'val=' + str(mcr_ind)  # start sel
                        ,
                        'en=' + str(0 if rec_on else 1)  # enabled
                    ]  # i=0
                            )
                ] + ([
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=GAP * 1 + HT_BTN * 0,
                                r=l_btn + WD_BTN,
                                b=0),
                        'cap=&View actions...',
                        'props=' +
                        str(0 if rec_on or 0 == lmcrs else 1)  # default
                        ,
                        'en=' +
                        str(0 if rec_on or 0 == lmcrs else 1)  # enabled
                    ]  # i=1
                            )
                ] if vw_acts else []) + [
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=GAP * 2 + HT_BTN * 1,
                                r=l_btn + WD_BTN,
                                b=0),
                        'cap=Hot&keys...',
                        'en=' +
                        str(0 if rec_on or 0 == lmcrs else 1)  # enabled
                    ]  # i=2 if vw_acts else i=1
                            )
                ] + [
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=GAP * 3 + HT_BTN * 2,
                                r=l_btn + WD_BTN,
                                b=0),
                        'cap=Re&name...',
                        'en=' +
                        str(0 if rec_on or 0 == lmcrs else 1)  # enabled
                    ]  # i=3 if vw_acts else i=2
                            )
                ] + [
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=GAP * 4 + HT_BTN * 3,
                                r=l_btn + WD_BTN,
                                b=0),
                        'cap=&Delete...',
                        'en=' +
                        str(0 if rec_on or 0 == lmcrs else 1)  # enabled
                    ]  # i=4 if vw_acts else i=3
                            )
                ] + [
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=GAP * 6 + HT_BTN * 5,
                                r=l_btn + WD_BTN,
                                b=0),
                        'cap=&Run!',
                        'props=' +
                        str(1 if not vw_acts and not rec_on else 0)  # default
                        ,
                        'en=' +
                        str(0 if rec_on or 0 == lmcrs else 1)  # enabled
                    ]  # i=5 if vw_acts else i=4
                            )
                ] + [
                    C1.join([
                        'type=label',
                        POS_FMT(l=l_btn,
                                t=GAP * 7 + HT_BTN * 6 + 3,
                                r=l_btn + int(WD_BTN / 3),
                                b=0), 'cap=&Times'
                    ]  # i=6 if vw_acts else i=5
                            )
                ] + [
                    C1.join([
                        'type=spinedit',
                        POS_FMT(l=l_btn + int(WD_BTN / 3) + GAP,
                                t=GAP * 7 + HT_BTN * 6,
                                r=l_btn + WD_BTN,
                                b=0),
                        'val=' + str(times),
                        'props=0,{},1'.format(self.dlg_prs.get('times', 1000)),
                        'en=' + str(0 if rec_on else 1)  # enabled
                    ]  # i=7 if vw_acts else i=6
                            )
                ] + [
                    C1.join([
                        'type=label',
                        POS_FMT(l=l_btn,
                                t=GAP * 8 + HT_BTN * 7 + 3,
                                r=l_btn + int(WD_BTN / 3),
                                b=0), 'cap=&Wait'
                    ]  # i=8 if vw_acts else i=7
                            )
                ] + [
                    C1.join([
                        'type=spinedit',
                        POS_FMT(l=l_btn + int(WD_BTN / 3) + GAP,
                                t=GAP * 8 + HT_BTN * 7,
                                r=l_btn + WD_BTN - 40,
                                b=0),
                        'val=' + str(waits),
                        'props=1,3600,1',
                        'en=' + str(0 if rec_on else 1)  # enabled
                    ]  # i=9 if vw_acts else i=8
                            )
                ] + [
                    C1.join([
                        'type=label',
                        POS_FMT(l=l_btn + WD_BTN - 40 + GAP,
                                t=GAP * 8 + HT_BTN * 7 + 3,
                                r=l_btn + WD_BTN,
                                b=0), 'cap=sec'
                    ]  # i=10 if vw_acts else i=9
                            )
                ] + [
                    C1.join([
                        'type=check',
                        POS_FMT(l=l_btn,
                                t=GAP * 9 + HT_BTN * 8,
                                r=l_btn + WD_BTN,
                                b=0), 'cap=While text c&hanges', 'val=' + chngs
                    ]  # i=11 if vw_acts else i=10
                            )
                ] + [
                    C1.join([
                        'type=check',
                        POS_FMT(l=l_btn,
                                t=GAP * 10 + HT_BTN * 9,
                                r=l_btn + WD_BTN,
                                b=0), 'cap=Until c&aret on last line', 'val=' +
                        endln
                    ]  # i=12 if vw_acts else i=11
                            )
                ] + [
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=GAP * 12 + HT_BTN * 11,
                                r=l_btn + WD_BTN,
                                b=0),
                        'cap={}'.format(
                            '&Stop record' if rec_on else '&Start record'),
                        'props=' +
                        str(1 if rec_on or 0 == lmcrs else 0)  # default
                    ]  # i=13 if vw_acts else i=12
                            )
                ] + [
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=GAP * 13 + HT_BTN * 12,
                                r=l_btn + WD_BTN,
                                b=0),
                        'cap=Canc&el record',
                        'en=' + str(1 if rec_on else 0)  # enabled
                    ]  # i=14 if vw_acts else i=13
                            )
                ] + [
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=HT_LST - HT_BTN * 2,
                                r=l_btn + WD_BTN,
                                b=0),
                        'cap=C&ustom...',
                        'en=' + str(0 if rec_on else 1)  # enabled
                    ]  # i=15 if vw_acts else i=14
                            )
                ] + [
                    C1.join([
                        'type=button',
                        POS_FMT(l=l_btn,
                                t=GAP + HT_LST - HT_BTN * 1,
                                r=l_btn + WD_BTN,
                                b=0), 'cap=&Close'
                    ]  # i=16 if vw_acts else i=15
                            )
                ] + ([
                    C1.join([
                        'type=memo',
                        POS_FMT(l=GAP + WD_LST + GAP + WD_BTN + GAP,
                                t=GAP,
                                r=GAP + WD_LST + GAP + WD_BTN + GAP + WD_ACTS,
                                b=GAP + HT_ACTS),
                        'val=' + mcr_acts,
                        'props=1,1,1'  # ro,mono,border
                    ]  # i=17
                            )
                ] if vw_acts else [])),
                apx.icase(
                    vw_acts and not rec_on,
                    0  # View
                    ,
                    not vw_acts and not rec_on,
                    0  # View
                    ,
                    vw_acts and rec_on,
                    11,
                    not vw_acts and rec_on,
                    10))  # start focus
            pass
            LOG and log('ans={}', ans)
            if ans is None: break  #while
            (ans_i, vals) = ans
            ans_s = apx.icase(
                False, '', vw_acts and ans_i == 1, 'view', vw_acts
                and ans_i == 2, 'hotkeys', not vw_acts and ans_i == 1,
                'hotkeys', vw_acts and ans_i == 3, 'rename', not vw_acts
                and ans_i == 2, 'rename', vw_acts and ans_i == 4, 'delete',
                not vw_acts and ans_i == 3, 'delete', vw_acts and ans_i == 5,
                'run', not vw_acts and ans_i == 4, 'run', vw_acts
                and ans_i == 12, 'rec', not vw_acts and ans_i == 7, 'rec',
                vw_acts and ans_i == 14, 'cancel', not vw_acts and ans_i == 13,
                'cancel', vw_acts and ans_i == 15, 'custom', not vw_acts
                and ans_i == 14, 'custom', vw_acts and ans_i == 16, 'close',
                not vw_acts and ans_i == 15, 'close', '?')
            mcr_ind = int(vals.splitlines()[0])
            times = int(vals.splitlines()[7 if vw_acts else 6])
            waits = int(vals.splitlines()[9 if vw_acts else 8])
            chngs = vals.splitlines()[11 if vw_acts else 10]
            endln = vals.splitlines()[12 if vw_acts else 11]
            pass
            LOG and log('mcr_ind,times,waits,chngs,endln={}',
                        (mcr_ind, times, waits, chngs, endln))

            if 0 != lmcrs and mcr_ind in range(lmcrs):
                mcr = self.macros[mcr_ind]
                self.last_mcr_id = mcr['id']

            if ans_s == 'close': break  #while
            if ans_s == 'custom':  #Custom
                custs = app.dlg_input_ex(
                    5, 'Custom dialog Macros',
                    'Height of macro list (min 450)',
                    str(self.dlg_prs.get('h_list', 400)),
                    'Width of macro list (min 200)',
                    str(self.dlg_prs.get('w_list', 500)),
                    'Width of action list (min 200, <=0-hide)',
                    str(self.dlg_prs.get('w_acts',
                                         500)), 'Width of buttons (min 150)',
                    str(self.dlg_prs.get('w_btn',
                                         150)), 'Max run times (min 100)',
                    str(self.dlg_prs.get('times', 1000)))
                if custs is not None:
                    self.dlg_prs['h_list'] = max(450, int(custs[0]))
                    self.dlg_prs['h_acts'] = self.dlg_prs['h_list']
                    self.dlg_prs['w_list'] = max(200, int(custs[1]))
                    self.dlg_prs['w_acts'] = max(200, int(
                        custs[2])) if int(custs[2]) > 0 else int(custs[2])
                    self.dlg_prs['w_btn'] = max(150, int(custs[3]))
                    self.dlg_prs['times'] = max(100, int(custs[4]))
                    open(MACROS_JSON, 'w').write(
                        json.dumps(
                            {
                                'ver': JSON_FORMAT_VER,
                                'list': self.macros,
                                'dlg_prs': self.dlg_prs
                            },
                            indent=4))
                continue  #while

            if mcr_ind not in range(lmcrs):
                app.msg_box('Select macro', app.MB_OK)
                continue  #while

            what = ''
            changed = False
            if False: pass

            elif ans_s == 'view':  #View
                continue  #while

            elif ans_s == 'rename':  #Rename
                mcr_nm = app.dlg_input(
                    'New name for: {}'.format(nmkys[mcr_ind]), mcr['nm'])
                if mcr_nm is None or mcr_nm == mcr['nm']: continue  #while
                while mcr_nm in [mcr['nm'] for mcr in self.macros]:
                    app.msg_box(
                        'Select other name.\nMacro names now are:\n\n' +
                        '\n'.join(nmkys), app.MB_OK)
                    mcr_nm = app.dlg_input(
                        'New name for: {}'.format(nmkys[mcr_ind]), mcr_nm)
                    if mcr_nm is None or mcr_nm == mcr['nm']:
                        break  #while mcr_nm
                if mcr_nm is None or mcr_nm == mcr['nm']: continue  #while
                what = 'rename'
                mcr['nm'] = mcr_nm
                changed = True

            elif ans_s == 'delete':  #Del
                if app.msg_box('Delete macro\n    {}'.format(nmkys[mcr_ind]),
                               app.MB_YESNO) != app.ID_YES:
                    continue  #while
                what = 'delete:' + str(mcr['id'])
                del self.macros[mcr_ind]
                mcr_ind = min(mcr_ind, len(self.macros) - 1)
                changed = True

            elif ans_s == 'hotkeys':  #Hotkeys
                app.dlg_hotkeys('cuda_macros,run,' + str(mcr['id']))
                keys = apx._json_loads(open(
                    keys_json).read()) if os.path.exists(keys_json) else {}
                changed = True

            elif ans_s == 'run':  #Run
                if (times == 0 and waits == 0 and chngs == '0'
                        and endln == '0'):
                    app.msg_box('Select stop condition', app.MB_OK)
                    continue
                self.run(mcr['id'], max(0, times), max(0, waits), chngs == '1',
                         endln == '1')
                return

            elif ans_s == 'rec' and not rec_on:  #Start record
                return ed.cmd(cmds.cmd_MacroStart)
            elif ans_s == 'rec' and rec_on:  #Stop record
                self.need_dlg = True
                return ed.cmd(
                    cmds.cmd_MacroStop
                )  # Return for clear rec-mode in StatusBar, will recall from on_macro
            elif ans_s == 'cancel' and rec_on:  #Cancel record
                return ed.cmd(cmds.cmd_MacroCancel
                              )  # Return for clear rec-mode in StatusBar

            if changed:
                self._do_acts(what)
示例#11
0
def symbol_menu_levels(levels=0):
    pass;                       log4fun=-1== 1  # Order log in the function
    if  app.app_api_version() >= '1.0.277' and \
        ed.get_prop(app.PROP_CODETREE_MODIFIED_VERSION) < ed.get_prop(app.PROP_MODIFIED_VERSION):
        ed.cmd(cmds.cmd_TreeUpdate)
    h_tree = app.app_proc(app.PROC_GET_CODETREE, '')
        
    def tree_items_to_list(props=None, id_node=0, prefix='', more_levels=1000):
        '''Get all tree nodes to "props" starting from id_node (e.g. 0)'''
        props = [] if props is None else props 
        nodes = app.tree_proc(h_tree, app.TREE_ITEM_ENUM, id_node)
        if not nodes:
            nodes = app.tree_proc(h_tree, app.TREE_ITEM_ENUM, id_node)
            if not nodes:
                return 
        for id_kid, cap in nodes:
            prop    = app.tree_proc(h_tree, app.TREE_ITEM_GET_PROPS, id_kid)
            rng     = app.tree_proc(h_tree, app.TREE_ITEM_GET_RANGE, id_kid)
            subs    = prop['sub_items']
            if rng[0]>=0:
                prop['rng'] = rng
                prop['_t']  = f('{}{}\t{}'
                                , prefix
                                , prop['text']
                                , f('{}:{}', 1+rng[1], 1+rng[3]))
                props.append(prop)
            if subs and more_levels:
                # need items with sub_items too
                tree_items_to_list(props, id_kid, prefix+' '*4, more_levels-1)
        return props
       #def tree_items_to_list
    
    old_api     = app.app_api_version() < '1.0.277'
    w           = get_hist('symbols.w', 600)
    h           = get_hist('symbols.h', 550)
    while True:
        props = tree_items_to_list(more_levels=(levels-1 if levels else 1000))
        if not props:
            ed.cmd(cmds.cmd_TreeUpdate)
            props = tree_items_to_list()
            if not props:
                return app.msg_status(_('No items in Code Tree'))

        items       = [p['_t'] for p in props]
        crt_row     = ed.get_carets()[0][1]
        covers      = [(p['rng'][3]-p['rng'][1], n) for n,p in enumerate(props) 
                        if p['rng'][1] <= crt_row <= p['rng'][3]]
        start_item  = min(covers)[1] if covers else 0
        res = dlg_menu(app.MENU_LIST+app.MENU_NO_FULLFILTER+app.MENU_EDITORFONT
            , w=w, h=h
            , sel=start_item
            , cap=_('Code Tree symbols')
                     + f(' ({})'    , len(items))
                     +(f(' (up {})' , levels    ) if levels else '')
            , its=items 
            + ([_('<Update Code Tree>')] if old_api else [])
            + [_('              <All levels>')]
            + [_('              <Only 1 up level>')]
            + [_('              <Only 2 up levels>')]
            + [_('              <Only 3 up levels>')]
            )
        if res is None: return
        if res==len(props) and old_api:
            ed.cmd(cmds.cmd_TreeUpdate)
            continue#while
        if res==0+len(props) + (1 if old_api else 0):
            levels  = 0
            continue#while
        if res==1+len(props) + (1 if old_api else 0):
            levels  = 1
            continue#while
        if res==2+len(props) + (1 if old_api else 0):
            levels  = 2
            continue#while
        if res==3+len(props) + (1 if old_api else 0):
            levels  = 3
            continue#while
        break
       #while
        
    x, y, x1, y1 = props[res]['rng']
    ed.set_caret(x, y)
示例#12
0
def _get_best_tree_path(row):
    """ Find node-path nearext to row: all nodes cover row or are all above/below nearest.
        Return
            [(widest_node_id,cap), (node_id,cap), ..., (smallest_node_id,cap)], gap
                list can be empty
                gap:  0 if row is covered
                     >0 if nearest node below
                     <0 if nearest node above
    """
    ed.cmd(cmds.cmd_TreeUpdate)
    ID_TREE = app.app_proc(app.PROC_SIDEPANEL_GET_CONTROL, 'Code tree')
    INF     = 0xFFFFFFFF
    if not ID_TREE: return [], INF
    NO_ID   = -1
    def best_path(id_prnt, prnt_cap=''):
        rsp_l   = []
        kids    = app.tree_proc(ID_TREE, app.TREE_ITEM_ENUM, id_prnt)
        pass;                  #log('>>id_prnt, prnt_cap, kids={}',(id_prnt, prnt_cap, len(kids) if kids else 0))
        if kids is None:
            pass;              #log('<<no kids',())
            return [], INF
        row_bfr, kid_bfr, cap_bfr = -INF, NO_ID, ''
        row_aft, kid_aft, cap_aft = +INF, NO_ID, ''
        for kid, cap in kids:
            pass;              #log('kid, cap={}',(kid, cap))
            cMin, rMin, \
            cMax, rMax  = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_SYNTAX_RANGE , kid) \
                            if app.app_api_version() < '1.0.226' else \
                          app.tree_proc(ID_TREE, app.TREE_ITEM_GET_RANGE        , kid)
            pass;              #log('? kid,cap, rMin,rMax,row={}',(kid,cap, rMin,rMax,row))
            if False:pass
            elif rMin<=row<=rMax:   # Cover!
                sub_l, gap_sub  = best_path(kid, cap)
                pass;          #log('? sub_l, gap_sub={}',(sub_l, gap_sub))
                if gap_sub == 0:    # Sub-kid also covers
                    pass;      #log('+ sub_l={}',(sub_l))
                    rsp_l   = [(kid, cap)] + sub_l
                else:               # The kid is best
                    pass;      #log('0 ',())
                    rsp_l   = [(kid, cap)]
                pass;          #log('<<! rsp_l={}',(rsp_l))
                return rsp_l, 0
            elif row_bfr                  < rMax            < row:
                row_bfr, kid_bfr, cap_bfr = rMax, kid, cap
                pass;          #log('< row_bfr, kid_bfr, cap_bfr={}',(row_bfr, kid_bfr, cap_bfr))
            elif row_aft                  > rMin            > row:
                row_aft, kid_aft, cap_aft = rMin, kid, cap
                pass;          #log('> row_aft, kid_aft, cap_aft={}',(row_aft, kid_aft, cap_aft))
           #for kid
        pass;                  #log('? row_bfr, kid_bfr, cap_bfr={}',(row_bfr, kid_bfr, cap_bfr))
        pass;                  #log('? row_aft, kid_aft, cap_aft={}',(row_aft, kid_aft, cap_aft))
        pass;                  #log('? abs(row_bfr-row), abs(row_aft-row)={}',(abs(row_bfr-row), abs(row_aft-row)))
        kid_x, cap_x, gap_x = (kid_bfr, cap_bfr, row_bfr-row) \
                            if abs(row_bfr-row) <= abs(row_aft-row) else \
                              (kid_aft, cap_aft, row_aft-row)
        pass;                  #log('kid_x, cap_x, gap_x={}',(kid_x, cap_x, gap_x))
        sub_l, gap_sub  = best_path(kid_x, cap_x)
        pass;                  #log('? sub_l,gap_sub ?? gap_x={}',(sub_l, gap_sub, gap_x))
        if abs(gap_sub) <= abs(gap_x):  # Sub-kid better
            rsp_l  = [(kid_x, cap_x)] + sub_l
            pass;              #log('<<sub bt: rsp_l, gap_sub={}',(rsp_l, gap_sub))
            return rsp_l, gap_sub
        # The kid is best
        rsp_l   = [(kid_x, cap_x)]
        pass;                  #log('<<bst: rsp_l, gap_x={}',(rsp_l, gap_x))
        return rsp_l, gap_x
       #def best_path
    lst, gap= best_path(0)
    pass;                      #log('lst, gap={}',(lst, gap))
    return lst, gap
示例#13
0
def find_tree_node():
    pass;                       log4fun=-1==-1  # Order log in the function
    HELP_C  = _('''
Search starts on Enter.
• A found node after current one will be selected.
• All found nodes are remembered and dialog can jump over them by [Shift+]Enter or by menu commands.
• If option "O" (wrapped search) is tuned on:
    - Search continues from the start, when end of the tree is reached
    - Jumps to previous/next nodes are looped too
• Option ".*" (regular expression) allows to use Python reg.ex. See "docs.python.org/3/library/re.html".
• Option "w" (whole words) is ignored if entered string contains not a word.
• If option "Close on success" (in menu) is tuned on, dialog will close after successful search.
• Option "Show full tree path" (in menu) shows in the statusbar the path of the found node (names of all parents).
• Command "Restore initial selection" (in menu) restores only first of initial carets.
    ''').strip()
    ed_crts = ed.get_carets()           # Carets at start
    opts    = d(reex=False,case=False,word=False,wrap=False,hist=[],clos=False,fpth=False)
    opts.update(get_hist('tree.find_node', opts))
    # Scan Tree
    ID_TREE = app.app_proc(app.PROC_SIDEPANEL_GET_CONTROL, 'Code tree')
    if not ID_TREE: return app.msg_status(_('No CodeTree'))
    if not app.tree_proc(ID_TREE, app.TREE_ITEM_ENUM, 0):   # 0 is root
        ed.cmd(cmds.cmd_TreeUpdate)                         # Try to build tree
    tree_t  = []        # [{nid:ID, sub:[{nid:ID, sub:{}, cap:'smth', path:['rt','smth']},], cap:'rt', path:[]},]
    tree_p  = []        # [,(ID, 'smth',['rt','smth']),]
    def scan_tree(id_prnt, tree_nds, path_prnt):
        nonlocal tree_p
        kids            = app.tree_proc(ID_TREE, app.TREE_ITEM_ENUM, id_prnt)
        if kids is None:    return None
        for nid, cap in kids:
            path        = path_prnt + [cap]
            tree_p     += [(nid, cap, path)]
            sub         = scan_tree(nid, [], path)
        return tree_nds
       #def scan_tree
    scan_tree(0, tree_t, [])    # 0 is root
    pass;                      #log('tree_t={}',pfrm100(tree_t)) if iflog(log4fun,_log4mod) else 0
    pass;                      #log('tree_p={}',pfrm100(tree_p)) if iflog(log4fun,_log4mod) else 0
        
    # How to select node
    def select_node(nid):
        app.tree_proc(ID_TREE, app.TREE_ITEM_SELECT, nid)
        c_min, r_min,   \
        c_max, r_max    = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_RANGE, nid)
        ed.set_caret(c_min, r_min)
       #def select_node
        
    # Ask
    MAX_HIST= apx.get_opt('ui_max_history_edits', 20)
    stbr    = None
    status  = lambda msg:  app.statusbar_proc(stbr, app.STATUSBAR_SET_CELL_TEXT, tag=1, value=msg)
    def add_to_hist(val, lst):
        """ Add/Move val to list head. """
        if val in lst:
            if 0 == lst.index(val):   return lst
            lst.remove(val)
        lst.insert(0, val)
        if len(lst)>MAX_HIST:
            del lst[MAX_HIST:]
        return lst
       #def add_to_hist
    compile_pttn= lambda    pttn_s, reex, case, word: re.compile(
                            pttn_s          if reex else
                      r'\b'+pttn_s+r'\b'    if word and re.match('^\w+$', pttn_s) else
                  re.escape(pttn_s)
                        ,   0 if case else re.I)
        
    prev_wt = None          # Prev what
    ready_l = []            # [(nid,cap|path,ndn)]
    ready_p = -1            # pos in ready_l
    nfnd_st = lambda: status(_('No suitable nodes'))
    ready_st= lambda: status(f('{pos}/{all}:  {cap}', pos=1+ready_p, all=len(ready_l), cap=ready_l[ready_p][1]))
    ready_er= lambda: status(_('Error'))
        
    def do_attr(ag, aid, data=''):
        nonlocal prev_wt
        prev_wt = ''
        return d(fid='what')
    
    def do_menu(ag, aid, data=''):
        def wnen_menu(ag, tag):
            nonlocal opts, prev_wt
            if   tag in ('prev','next'):    return do_next(ag, tag)
            if   tag in ('fpth','clos'):    prev_wt = '';   opts[tag] = not opts[tag]
            elif tag=='help':               app.msg_box(HELP_C, app.MB_OK)
            elif tag=='rest':               ed.set_caret(*ed_crts[0]);      return None
            return []
           #def wnen_menu
        
        ag.show_menu(
            [ d(    tag='help'  ,cap=_('&Help...')
            ),d(                 cap='-'
            ),d(    tag='prev'  ,cap=_('Find &previous')                                ,key='Shift+Enter'
            ),d(    tag='next'  ,cap=_('F&ind next')                                    ,key='Enter'
            ),d(                 cap='-'
            ),d(                 cap=_('&Options')  ,sub=
                [ d(tag='fpth'  ,cap=_('Show full tree path')   ,ch=opts['fpth']
                ),d(tag='clos'  ,cap=_('Close on success')      ,ch=opts['clos']
            )]),d(               cap='-'
            ),d(    tag='rest'  ,cap=_('Restore initial selection and close dialog &=') ,key='Shift+Esc'
            )]
        ,   aid
        ,   cmd4all=wnen_menu                                   # Set cmd=wnen_menu for all nodes
        )
        return d(fid='what')
       #def do_menu
    
    def do_next(ag, aid, data=''):
        if not ready_l:         return d(fid='what')
        nonlocal ready_p
        ready_n = ready_p + (-1 if aid=='prev' else 1)
        ready_n = ready_n % len(ready_l) if opts['wrap'] else max(0, min(len(ready_l)-1, ready_n), 0)
        pass;                  #log('ready_n,ready_p={}',(ready_n,ready_p)) if iflog(log4fun,_log4mod) else 0
        if ready_p == ready_n:  return d(fid='what')
        ready_p = ready_n
        ready_st()
        select_node(ready_l[ready_p][0])
        return d(fid='what')
       #def do_next
    
    def do_find(ag, aid, data=''):
        nonlocal opts, tree_p, prev_wt, ready_l, ready_p
        # What/how/where will search
        what        = ag.val('what')
        if prev_wt==what and ready_l:
            return do_next(ag, 'next')
        prev_wt  = what
        pass;                  #log('what={}',(what)) if iflog(log4fun,_log4mod) else 0
        if not what:
            ready_l, ready_p    = [], -1
            return d(fid='what')
        opts['hist']= add_to_hist(what, opts['hist'])
        opts.update(ag.vals(['reex','case','word','wrap']))
        pass;                  #log('opts={}',(opts)) if iflog(log4fun,_log4mod) else 0
        tree_sid    = app.tree_proc(ID_TREE, app.TREE_ITEM_GET_SELECTED)    # cur
        nodes       = tree_p                                                # To find from top
        if tree_sid and opts['clos']:                                       # To find from cur
            # Trick: [..,i,sid]+[j,..]   switch to   [j,..] or [j,..]+[..,i]  to search first after cur
            nids    = [nid for nid, cap, path in tree_p]
            pos     = nids.index(tree_sid)
            nodes   = tree_p[pos+1:] + (tree_p[:pos] if opts['wrap'] else [])
        # Search
        ready_l = []
        tree_ndn= -1
        try:
            pttn_r  = compile_pttn(what, opts['reex'], opts['case'], opts['word'])
        except:
            ready_er()
            return d(ctrls=[('what',d(items=opts['hist']))]
                    ,fid='what')
        for ndn, (nid, cap, path) in enumerate(nodes):
            if not pttn_r.search(cap):  continue
            if opts['clos']:
                select_node(nid)
                return None         # Close dlg
            ready_l+= [(nid, ' / '.join(path) if opts['fpth'] else cap, ndn)]
            tree_ndn= ndn if ndn==tree_sid else tree_ndn
        pass;                  #log('ready_l={}',(ready_l)) if iflog(log4fun,_log4mod) else 0
        ready_p = -1    if not ready_l  else \
                  0     if not tree_sid else \
                  first_true(enumerate(ready_l), 0, (lambda n_nid_cap_ndn: n_nid_cap_ndn[1][2]>tree_ndn))[0]
        pass;                  #log('ready_p={}',(ready_p)) if iflog(log4fun,_log4mod) else 0
        # Show results
        if ready_p!=-1:
            select_node(ready_l[ready_p][0])
            if opts['clos']:
                return None         # Close dlg
            ready_st()
        else:
            nfnd_st()
        return d(ctrls=[('what',d(items=opts['hist']))]
                ,fid='what')
       #def do_find
    
    def do_key_down(ag, key, data=''):
        scam    = data if data else app.app_proc(app.PROC_GET_KEYSTATE, '')
        pass;                  #log('key,data,scam={}',(key,data,scam)) if iflog(log4fun,_log4mod) else 0
        if 0:pass
        elif (scam,key)==('s',VK_ENTER):        # Shift+Enter
            ag.update(do_next(ag, 'prev'))
        elif (scam,key)==('s',VK_ESCAPE):       # Shift+Esc
            ed.set_caret(*ed_crts[0])
            return None
        else: return [] # Nothing
        return False    # Stop event
       #def do_key_down
    
    ag      = DlgAg(
        form    =dict(cap=_('Find tree node'), w=365, h=58, h_max=58
                     ,on_key_down=do_key_down
                     ,border=app.DBORDER_TOOLSIZE
#                    ,resize=True
                     )
    ,   ctrls   =[0
  ,('find',d(tp='bttn',y=0          ,x=-99      ,w=44   ,cap=''     ,sto=False  ,def_bt=T           ,on=do_find         ))  # Enter
  ,('reex',d(tp='chbt',tid='what'   ,x=5+38*0   ,w=39   ,cap='.&*'  ,hint=_('Regular expression')   ,on=do_attr         ))  # &*
  ,('case',d(tp='chbt',tid='what'   ,x=5+38*1   ,w=39   ,cap='&aA'  ,hint=_('Case sensitive')       ,on=do_attr         ))  # &a
  ,('word',d(tp='chbt',tid='what'   ,x=5+38*2   ,w=39   ,cap='"&w"' ,hint=_('Whole words')          ,on=do_attr         ))  # &w
  ,('wrap',d(tp='chbt',tid='what'   ,x=5+38*3   ,w=39   ,cap='&O'   ,hint=_('Wrapped search')       ,on=do_attr         ))  # &/
  ,('what',d(tp='cmbx',y  =5        ,x=5+38*4+5 ,w=155  ,items=opts['hist']                                     ,a='r>' ))  # 
  ,('menu',d(tp='bttn',tid='what'   ,x=320      ,w=40   ,cap='&='                                   ,on=do_menu ,a='>>' ))  # &=
  ,('stbr',d(tp='stbr'              ,x=0        ,r=365                                  ,ali=ALI_BT             ,a='r>' ))  # 
                ][1:]
    ,   fid     ='what'
    ,   vals    = {k:opts[k] for k in ('reex','case','word','wrap')}
                          #,options={'gen_repro_to_file':'repro_dlg_find_tree_node.py'}
    )
    stbr    = ag.chandle('stbr')
    app.statusbar_proc(stbr, app.STATUSBAR_ADD_CELL             , tag=1)
    app.statusbar_proc(stbr, app.STATUSBAR_SET_CELL_AUTOSTRETCH , tag=1, value=True)
    ag.show(lambda ag: set_hist('tree.find_node', upd_dict(opts, ag.vals(['reex','case','word','wrap']))))