• Enez Houad

    @mikael Thanks for your reactivity !

    posted in Pythonista read more
  • Enez Houad

    @mikael , I regularly use your modules and I thank you for it. Unfortunately, since the last version of ui3, I have an error when I want to use it.
    Here is the Traceback :

    Traceback (most recent call last):
      File "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/ui3-master/sheet.py", line 7, in <module>
        from ui3.anchor import *
      File "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/ui3-master/ui3/__init__.py", line 12, in <module>
        from ui3.anchor import *
      File "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/ui3-master/ui3/anchor/__init__.py", line 821, in <module>
        via_screen,
    NameError: name 'via_screen' is not defined ```

    posted in Pythonista read more
  • Enez Houad

    @cvp Thanks a lot ! I’m happy to see that I progress slowly…
    I had found textView().becomeFirstResponder() but couldn’t find to witch element it had to be applied. The _get_editor_tab is not documented ! To find it, do you open editor.py in the site-packages of Standard Library ?
    It's very instructive πŸ€“, I'm going to end up managing on my own. πŸ˜‰

    posted in Pythonista read more
  • Enez Houad

    @cvp I learn a lot adapting your scripts to my needs !
    You will find after this message my/your script to add a keyboard icon in the titlebar to call my script to add my special key row to the keyboard.
    The system is rather practical, but to make the handling as transparent as possible : when I add my key row, I hide the keyboard with tv.endEditing(True), and I would like to make it reappear with my special key row : but I’ve not found a command as simple as tv.startEditing πŸ™ ; it’s perharps possible to simulate a touch in the TextView, but I neither can’t find a solution to do it πŸ₯Ά
    After several hours of searching, I throw in the towel and ask for help…πŸ₯΅

    from objc_util import *
    import ui
    from ui3.sfsymbol import *
    
    w = ObjCClass('UIApplication').sharedApplication().keyWindow()
    main_view = w.rootViewController().view()
    
    def get_toolbar(view):
        # get main editor toolbar, by recursively walking the view
        sv = view.subviews()
        for v in sv:
            if v._get_objc_classname().startswith(b'OMTabViewToolbar'):
                return v
            tb = get_toolbar(v)
            if tb:
                return tb
                
    # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
    
    def keyboard_btn_action(sender):
        
        def run_script(scriptPath):
            import os
            from objc_util import ObjCInstance,ObjCClass
        
            dir = os.path.expanduser(scriptPath)
            I3=ObjCClass('PYK3Interpreter').sharedInterpreter()
            I3.runScriptAtPath_argv_resetEnvironment_(dir, [''], True)
    
        iCloudPath = "/private/var/mobile/Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents/"
        iPadPath = '~/Documents/'
        scriptPath = 'PROJETS/KEYBOARD/my_special_key_row.py'
        run_script(iCloudPath + scriptPath)
                
    # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
    
    def create_keyboard_button(action,index=0):
        global __persistent_views
        
        assert(callable(action))
        tb = get_toolbar(main_view)
            
        try:
            __persistent_views
        except NameError:
            __persistent_views={}
            
        #check for existing button in this index and delete if needed
        remove_toolbar_button(index)    
        btn = ui.Button()
        btn.frame = (110, 24, 40, 40)
        
        if ui.get_ui_style() == 'dark':
            btn.tint_color = 'white' 
        else:
            btn.tint_color = '#0D89B5' 
        btn.image = SymbolImage('keyboard', point_size=14, weight=THIN, scale=SMALL)
        btn.image = btn.image.with_rendering_mode(ui.RENDERING_MODE_AUTOMATIC)
                
        btn.action=action
        btn_obj=ObjCInstance(btn)
        __persistent_views[index]=(btn,action)
        tb.superview().superview().addSubview_(btn_obj) # in front of all buttons
        
        return btn
        
    # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
        
    def remove_toolbar_button(index):
        global __persistent_views
        
        try:
            btn,action = __persistent_views.pop(index)
            btn.action= None
            ObjCInstance(btn).removeFromSuperview()
        except KeyError:
            pass
    
    # ===================================================================
    
    #if __name__=='__main__': # if imported by pythonista startup   
            
    create_keyboard_button(keyboard_btn_action) 
            
    create_keyboard_button(keyboard_btn_action)
    
    

    posted in Pythonista read more
  • Enez Houad

    Here is my scrolling special key row to replace the standard one.
    This script is a mix between @cvpe's script AddButtonsToPythonistaKeyboard https://github.com/cvpe/Pythonista-scripts/blob/master/AddButtonsToPythonistaKeyboard.py
    and my own work.
    It uses module ui3.sfsymbol of @mikaelho https://github.com/mikaelho/ui3
    Thanks for all their work for Pythonista's community.
    It certainly contains errors as I am not an expert coder like the majority of you but it does work for me πŸ˜‰
    Feel free to improve and adapt it to your needs!

    # =================================================================
    # This script is a mix between @cvpe's script AddButtonsToPythonistaKeyboard 
    # https://github.com/cvpe/Pythonista-scripts/blob/master/AddButtonsToPythonistaKeyboard.py
    # and my own work.
    # It uses module ui3.sfsymbol of @mikaelho
    # https://github.com/mikaelho/ui3
    # 
    # enez.houad@free.fr
    # =================================================================
    
    import ui, editor, clipboard
    from objc_util import *
    from ui3.sfsymbol import *
    
    @on_main_thread
    def tv_find(tv):
        import console, re
        
        tv.find = console.input_alert('Expression Γ  rechercher :', '', tv.find, hide_cancel_button=True)
        txt = tv.find
        
        for sv in tv.subviews():
            if 'SUIButton_PY3' in str(sv._get_objc_classname()):
                sv.removeFromSuperview()
        if txt == '':
            return
        t = str(tv.text())
        
        for m in re.finditer(txt, t):
            st,en = m.span()
            p1 = tv.positionFromPosition_offset_(tv.beginningOfDocument(), st)
            p2 = tv.positionFromPosition_offset_(tv.beginningOfDocument(), en)
            rge = tv.textRangeFromPosition_toPosition_(p1,p2)
            rect = tv.firstRectForRange_(rge)
            x,y = rect.origin.x,rect.origin.y
            w,h = rect.size.width,rect.size.height
            
            l = ui.Button()
            l.frame = (x,y,w,h)
            if '|' not in txt:
                l.background_color = (1,0,0,0.2)
            else:
                # search multiple strings
                wrds = txt.split('|')
                idx = wrds.index(t[st:en])
                cols = [(1,0,0,0.2), (0,1,0,0.2), (0,0,1,0.2), (1,1,0,0.2), (1,0,1,0.2), (0,1,1,0.2)]
                col = cols[idx % len(cols)]
                l.background_color = col
            l.corner_radius = 4
            l.border_width = 1
            tv.addSubview_(l)       
        
    # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
    
    def key_pressed(sender):
        
        tv = sender.objc_instance.firstResponder() # associated TextView  
        
        cursor = tv.offsetFromPosition_toPosition_(tv.beginningOfDocument(),     tv.selectedTextRange().start()) # get actual cursor position
    
        if sender.name == 'tab':
            tv.insertText_('\t')
        
        elif sender.name == 'paste':
            tv.insertText_(clipboard.get()) 
            
        elif sender.name == 'undo':
            tv.undoManager().undo()
            
        elif sender.name == 'redo':
            tv.undoManager().redo()
        
        elif sender.name == 'del_right':
            # delete at right = delete at left of next
            if cursor == (len(str(tv.text()))-1): # already after last character
                return
            cursor_position = tv.positionFromPosition_offset_(tv.beginningOfDocument(), cursor+1)
            tv.selectedTextRange = tv.textRangeFromPosition_toPosition_(cursor_position, cursor_position)
            tv.deleteBackward()     
            
        elif sender.name == 'find':
            tv_find(tv)
            
        elif sender.name == 'line-':
            tv.insertText_('# ' + 65 * 'β€”')
        elif sender.name == 'line=':
            tv.insertText_('# ' + 65 * '=')
        elif sender.name == 'line#':
            tv.insertText_(67 * '#')
            
        else: # all other keys > insert button title
            tv.insertText_(sender.title)
        
    # ===================================================================
        
    class SpecialKeyRow(ui.View):
        
        def __init__(self, pad, *args, **kwargs):
            
            self.pad = pad
        
            sw, sh = ui.get_screen_size()   
            self.uiStyle = ui.get_ui_style()
            
            self.buttonsList = []
            self.buttonWidth = (sw - (2*8) - (24*4)) / 25
            self.buttonHeight = 40
            
            # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
            # MAIN VIEW 
        
            self.width, self.height = sw, 50
            self.alpha = 0.98
            
            # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
            # SCROLL VIEW
            
            sv = ui.ScrollView(name='scrollview')
            sv.width, sv.height = (sw, 50)
            sv.content_size = (2*sw, 50)
            sv.bounces = False
            sv.shows_horizontal_scroll_indicator = False
            sv.paging_enabled = True
            sv.x, sv.y = (0, 0)
            colorDict = {'light':'#D6D8DD', 'dark':'#343639'}
            sv.background_color = colorDict[self.uiStyle]
            
            self.add_subview(sv)
            
            # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
            # BUTTONS IN SCROLL VIEW
            # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
    
            for pad_elem in self.pad:
                if not 'style' in pad_elem: bStyle = 'light'
                else: bStyle = pad_elem['style']
                if 'title' in pad_elem:
                    b = self.add_text_button(name=pad_elem['key'], title=pad_elem['title'], style=bStyle)
                elif 'symbol' in pad_elem:
                    b = self.add_symbol_button(name=pad_elem['key'], symbol_name=pad_elem['symbol'], style=bStyle)
                self.add_scrollview_button(b)
            
        # ===================================================================
             
        def add_scrollview_button(self, b):
            b.y = 10
            if self.buttonsList == []: b.x = 8 # 1er bouton
            else:
                lastButton = self.buttonsList[-1]
                b.x = lastButton.x + lastButton.width + 4 # intervalle 4 px
                if len(self.buttonsList) == 25: b.x += 12 # 2e page
            b.action = key_pressed
            retain_global(b)
            self['scrollview'].add_subview(b)
            self.buttonsList.append(b)
                
        # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
        
        def add_text_button(self, name='', title='', width=40, style='light'):
            b = self.add_button(name, style)
            b.title = title
            b.font = ('<system>', 18)
            if width == None: b.width = ui.measure_string(b.title,font=b.font)[0] + 28
            else: b.width = self.buttonWidth        
            return b
            
        # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
        
        def add_symbol_button(self, name='', symbol_name='', style='light'):
            b = self.add_button(name, style)
            symbol_image = SymbolImage(symbol_name, point_size=11, weight=LIGHT, scale=SMALL)
            b.image = symbol_image  
            b.width = self.buttonWidth  
            return b
            
        # β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
        
        def add_button(self, name='', backgroundStyle='light'):
            
            b = ui.Button(name=name)
            b.corner_radius = 8
            
            colorsDict = {  'light' :({'light':'#FFFFFF', 'dark':'#B4B9C1'}, 'black'), 
                            'dark'  :({'light':'#717274', 'dark':'#4D4F50'}, 'white') }
            b.background_color = colorsDict[self.uiStyle][0][backgroundStyle]
            b.tint_color = colorsDict[self.uiStyle][1]
            
            b.alpha = self.alpha
            
            b.font = ('<system>', 18)
            b.height = self.buttonHeight        
            return b
                    
    # ===================================================================
    
    @on_main_thread
    def AddButtonsToPythonistaKeyboard(pad=None):
        
        def numeric_keys(): 
            list = []
            for i in range(1, 10):
                list.append({'key':str(i), 'title':str(i)})
            list.append({'key':'0', 'title':'0'})
            return list
            
        if not pad:     
            pad = [
                    {'key':'tab', 'symbol':'arrow.right.to.line.alt'},              
                
                    {'key':'undo', 'symbol':'arrow.uturn.left', 'style':'dark'},
                    {'key':'redo','symbol':'arrow.uturn.right', 'style':'dark'},
                    
                    {'key':'paste', 'symbol':'doc.on.clipboard'},
                
                    {'key':'#', 'title':'#'},
                    {'key':'_', 'title':'_'},
                
                    {'key':"'", 'title':"'"},
                    {'key':'"', 'title':'"'},
                    {'key':"'''", 'title':"'''"},
                
                    {'key':'(', 'title':'('},
                    {'key':')', 'title':')'},           
                    {'key':'[', 'title':'['},
                    {'key':']', 'title':']'},
                    {'key':'{', 'title':'{'},
                    {'key':'}', 'title':'}'},
                
                    {'key':'+', 'title':'+'},
                    {'key':'-', 'title':'-'},
                    {'key':'*', 'title':'*'},
                    {'key':'/', 'title':'/'},
                    {'key':"\\", 'title':"\\"},
                
                    {'key':'<', 'title':'<'},
                    {'key':'>', 'title':'>'},
                    {'key':'=', 'title':'='},
                    {'key':':', 'title':':'},
                
                    {'key':'del_right', 'symbol':'delete.right', 'style':'dark'},
                
                    {'key':'find', 'symbol':'magnifyingglass', 'style':'dark'}
                    ]
                    
            pad += numeric_keys() 
            
            pad += [
                    {'key':'+', 'title':'+'},
                    {'key':'-', 'title':'-'},
                    {'key':'*', 'title':'*'},
                    {'key':'/', 'title':'/'},
                    {'key':'<', 'title':'<'},
                    {'key':'>', 'title':'>'},
                    {'key':'=', 'title':'='},
                
                    {'key':'line-', 'title':'---'},
                    {'key':'line=', 'title':'==='},
                    {'key':'line#', 'title':'###'}
                    ]   
            
        ev = editor._get_editor_tab().editorView()
        tv = ev.textView()
        
        v = SpecialKeyRow(pad)                        
        vo = ObjCInstance(v)  
    
        retain_global(v)
        
        tv.setInputAccessoryView_(vo)   # attach accessory to textview
        tv.find = ''
        
    # ===================================================================
        
    if __name__ == '__main__':
        AddButtonsToPythonistaKeyboard() ```

    posted in Pythonista read more
  • Enez Houad

    @cvp Thank’s a lot Magic cvpπŸ‘πŸ‘πŸ‘ πŸ™

    posted in Pythonista read more
  • Enez Houad

    @cvp Thanks a lot for your work. But my goal is to get a reduced row of keys as I think that the original one is to large for the small screen of my iPad mini 4. I regret that it’s not possible to assign the fonction to a normal ui button.

    posted in Pythonista read more
  • Enez Houad

    @cvp Please, how do you insert directly your pictures in comments ?

    posted in Pythonista read more
  • Enez Houad

    The only solution I've found is to make my own special key row with the help of the cvp example ;-). It's quite easy for normal keys, but I don't find solution to implement the undo/redo key? Perhaps with objC ?

    posted in Pythonista read more
  • Enez Houad

    I have been using Pythonista occasionally for two years now. With the help of the forum and by rummaging through the web, I manage to make some nice little applications. However, I regularly come up against basic problems related to my lack of Python skills. This is the case today ;-)
    I can't understand why my script doesn't work.
    I just want to make a class of Buttons... but my title doesn't display.
    My mistake must be stupid, but I can't find it!

    import ui
    
    class MyButton (ui.View):
    
        def __init__(self, *args, **kwargs):        
            self.btn = ui.Button()
            for name in kwargs.keys():
                value = kwargs[name]
                self.__setattr__(name, value)       
            self.add_subview(self.btn)  
                    
        def __setattr__(self, name, value):     
            print(f'β€’ setattr : {name} = {value}')      
            if name != 'btn':
                self.btn.__setattr__(name, value)           
            super().__setattr__(name, value)
    
    if __name__ == '__main__':
    
        mainView = ui.View( name='MyButton Demo',
                            bg_color='lightgrey',
                            frame=(0, 0, 400, 400))
        
        myBtn = MyButton(   name='MyButton', 
                            title='Press me', 
                            width=200)
        
        myBtn.center = mainView.center
        myBtn.y = 200
        myBtn.background_color = 'red'
        myBtn.tint_color = 'white'
        
        mainView.add_subview(myBtn)
    
        mainView.present('sheet')
    
    

    posted in Pythonista read more
  • Enez Houad

    @mikael, Perfect πŸ‘πŸ‘πŸ™πŸ‘
    Thank you very much, I would find it hard to do without Scripter!

    posted in Pythonista read more
  • Enez Houad

    @mikael, Yes, I’ve updated Scripter (even uninstall and reinstall) and restarted Pythonista. And now… it works the first time, doesn’t the second and crash the third !

    posted in Pythonista read more
  • Enez Houad

    @mikael , unfortunately, the problem persists ! Do I need to reinstall something ?

    posted in Pythonista read more
  • Enez Houad

    @mikael , I’ve got a simular problem ! My animations with calls to scripter only works one time 😒. I need to restart Pythonista !
    I take this opportunity to thank you for your fantastic modules. iPadOS 14.3 beta on iPad mini 4

    posted in Pythonista read more
  • Enez Houad

    Has someone found a solution ? πŸ₯΅ the problem appears quite all the time for me and it’s really difficult to type text in rhe reduced special key row - I’ve got an iPad mini and the keyboard is small ;-)

    posted in Pythonista read more
  • Enez Houad

    @cvp Perfect, it works for me πŸ‘ always so impressive πŸ‘

    posted in Pythonista read more
  • Enez Houad

    @mikael, this is not only a iPhone problem as it appears on my iPad mini 4 with both orientations : portrait and landscape.
    It's a pity that there is no other solution than to use a fullscreen present mode as I only wanted to present a choice view with a tableView, never mind I will adapt !

    posted in Pythonista read more
  • Enez Houad

    I’ve not been using Pythonista for a long time, ios version have changed and now I have some problems with my scripts :
    The first is that my keyboard loose the extra line at the top, but I’ve seen on the forum that I’m the only one ;-) the second (but my search on the forum does’nt help me to find a solution - my bad english is really a problem) is that now a view in sheet mode close when I slide down with one finger. I would like to block this process.
    Thanks for a solution !

    posted in Pythonista read more
  • Enez Houad

    Merci beaucoup !

    posted in Pythonista read more
Internal error.

Oops! Looks like something went wrong!