Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Ui code editor questions
-
Hi is it possible to display matching paired brackets /curly braces etc? I’m sure this used to be the case.ie if you had a JSON file and selected a curly brace it matching brace would be highlighted /selected in correct location.
Is it possible to change the extra keyboard shortcuts above main virtual keyboard to appear as one large spaced line of options rather than two v small menus on the left and right? Is this an option as again I’m sure it didn’t used to look like this.
Cheers
Rich -
-
@rb it is possible via a script defined as a Pythonista tool, adding an additional key in Pythonista keyboard.
Example here-under only shows how to find next ending character, not really the matching pair, but this script only to show the way.Put your cusor on a ( or [ or {, tap the "pair" button
and you will get this
To erase special backgrounds, tap pair with cursor on any other characterimport editor from objc_util import * import ui def key_pressed(sender): import ui from objc_util import ObjCClass tv = sender.objc_instance.firstResponder() # associated TextView # get actual cursor position cursor = tv.offsetFromPosition_toPosition_(tv.beginningOfDocument(), tv.selectedTextRange().start()) if sender.name == 'pair': for sv in tv.subviews(): if 'SUIButton_PY3' in str(sv._get_objc_classname()): sv.removeFromSuperview() pairs = {'(':')','[':']','{':'}'} t = str(tv.text())[cursor] if t not in pairs: return ts = pairs[t] t = str(tv.text())[cursor+1:] cursor += 1 while True: try: t = str(tv.text())[cursor] except: return if t == ts: p1 = tv.positionFromPosition_offset_(tv.beginningOfDocument(), cursor) p2 = tv.positionFromPosition_offset_(tv.beginningOfDocument(), cursor+1) rge = tv.textRangeFromPosition_toPosition_(p1,p2) rect = tv.firstRectForRange_(rge) # CGRect 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) l.background_color = (1,0,0,0.2) l.corner_radius = 4 l.border_width = 1 tv.addSubview_(l) break cursor += 1 else: # normal key tv.insertText_(sender.title) return # set cursor cursor_position = tv.positionFromPosition_offset_(tv.beginningOfDocument(), cursor) tv.selectedTextRange = tv.textRangeFromPosition_toPosition_(cursor_position, cursor_position) class MyView(ui.View): def __init__(self, pad, *args, **kwargs): #super().__init__(self, *args, **kwargs) self.width = ui.get_screen_size()[0] # width of keyboard = screen self.background_color = 'lightgray'#(0,1,0,0.2) self.h_button = 32 self.pad = pad # build buttons for pad_elem in self.pad: if pad_elem['key'] in ('nul', 'new row'): # free space or new row continue button = ui.Button() # Button for user functionnality button.name = pad_elem['key'] button.background_color = 'white' # or any other color button.tint_color = 'black' button.corner_radius = 5 button.font = ('<system>',self.h_button - 8) button.title = '' if 'title' in pad_elem: button.title = pad_elem['title'] elif 'icon' in pad_elem: button.image = ui.Image.named(pad_elem['icon']).with_rendering_mode(ui.RENDERING_MODE_ORIGINAL) else: button.title = pad_elem['key'] button.action = key_pressed retain_global(button) # see https://forum.omz-software.com/topic/4653/button-action-not-called-when-view-is-added-to-native-view self.add_subview(button) self.layout() def layout(self): import ui #print('layout') # supports changing orientation #print(ui.get_screen_size()) dx = 8 dy = 2 x0 = 15 y0 = 10 dx_middle = 25 y = y0 x = x0 w_button = (ui.get_screen_size()[0] - 2*x0 - 17*dx - dx_middle)/18 for pad_elem in self.pad: nw = pad_elem.get('width', 1) wb = w_button*nw + dx*(nw-1) if (x + wb + dx) > self.width: y = y + self.h_button + dy x = x0 if pad_elem['key'] == 'nul': # let free space x = x + wb + dx continue elif pad_elem['key'] == 'new row': # new row y = y + self.h_button + dy x = x0 continue button = self[pad_elem['key']] xb = x + dx_middle if (x+wb) > self.width/2 else x button.frame = (xb,y,wb,self.h_button) if button.title != '': font_size = self.h_button - 8 while True: d = ui.measure_string(button.title,font=(button.font[0],font_size))[0]+4 if d <= wb: break font_size = font_size - 1 button.font = (button.font[0],font_size) x = x + wb + dx self.height = y + self.h_button + dy @on_main_thread def AddButtonsToPythonistaKeyboard(pad=None): ev = editor._get_editor_tab().editorView() tv = ev.textView() #print(tv._get_objc_classname()) #print(dir(tv)) # create ui.View for InputAccessoryView above keyboard v = MyView(pad) # view above keyboard vo = ObjCInstance(v) # get ObjectiveC object of v retain_global(v) # see https://forum.omz-software.com/topic/4653/button-action-not-called-when-view-is-added-to-native-view tv.setInputAccessoryView_(vo) # attach accessory to textview tv.strfind = '' if __name__ == '__main__': AddButtonsToPythonistaKeyboard(pad=[{'key':'pair'}])
-
@rb I'm sure we could do the same via an user menu, like
-
@rb real pairing
With
import editor from objc_util import * import ui def key_pressed(sender): import ui from objc_util import ObjCClass tv = sender.objc_instance.firstResponder() # associated TextView # get actual cursor position cursor = tv.offsetFromPosition_toPosition_(tv.beginningOfDocument(), tv.selectedTextRange().start()) if sender.name == 'pair': for sv in tv.subviews(): if 'SUIButton_PY3' in str(sv._get_objc_classname()): sv.removeFromSuperview() pairs = {'(':')','[':']','{':'}'} t = str(tv.text())[cursor] if t not in pairs: return cursors = [cursor] ts = pairs[t] #tc = str(tv.text())[cursor+1:] cursor += 1 n = 0 while True: try: tc = str(tv.text())[cursor] except: return if tc == t: n = n + 1 elif tc == ts: if n == 0: cursors.append(cursor) for cursor in cursors: p1 = tv.positionFromPosition_offset_(tv.beginningOfDocument(), cursor) p2 = tv.positionFromPosition_offset_(tv.beginningOfDocument(), cursor+1) rge = tv.textRangeFromPosition_toPosition_(p1,p2) rect = tv.firstRectForRange_(rge) # CGRect 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) l.background_color = (1,0,0,0.2) l.corner_radius = 4 l.border_width = 1 tv.addSubview_(l) break n = n - 1 cursor += 1 else: # normal key tv.insertText_(sender.title) return # set cursor cursor_position = tv.positionFromPosition_offset_(tv.beginningOfDocument(), cursor) tv.selectedTextRange = tv.textRangeFromPosition_toPosition_(cursor_position, cursor_position) class MyView(ui.View): def __init__(self, pad, *args, **kwargs): #super().__init__(self, *args, **kwargs) self.width = ui.get_screen_size()[0] # width of keyboard = screen self.background_color = 'lightgray'#(0,1,0,0.2) self.h_button = 32 self.pad = pad # build buttons for pad_elem in self.pad: if pad_elem['key'] in ('nul', 'new row'): # free space or new row continue button = ui.Button() # Button for user functionnality button.name = pad_elem['key'] button.background_color = 'white' # or any other color button.tint_color = 'black' button.corner_radius = 5 button.font = ('<system>',self.h_button - 8) button.title = '' if 'title' in pad_elem: button.title = pad_elem['title'] elif 'icon' in pad_elem: button.image = ui.Image.named(pad_elem['icon']).with_rendering_mode(ui.RENDERING_MODE_ORIGINAL) else: button.title = pad_elem['key'] button.action = key_pressed retain_global(button) # see https://forum.omz-software.com/topic/4653/button-action-not-called-when-view-is-added-to-native-view self.add_subview(button) self.layout() def layout(self): import ui #print('layout') # supports changing orientation #print(ui.get_screen_size()) dx = 8 dy = 2 x0 = 15 y0 = 10 dx_middle = 25 y = y0 x = x0 w_button = (ui.get_screen_size()[0] - 2*x0 - 17*dx - dx_middle)/18 for pad_elem in self.pad: nw = pad_elem.get('width', 1) wb = w_button*nw + dx*(nw-1) if (x + wb + dx) > self.width: y = y + self.h_button + dy x = x0 if pad_elem['key'] == 'nul': # let free space x = x + wb + dx continue elif pad_elem['key'] == 'new row': # new row y = y + self.h_button + dy x = x0 continue button = self[pad_elem['key']] xb = x + dx_middle if (x+wb) > self.width/2 else x button.frame = (xb,y,wb,self.h_button) if button.title != '': font_size = self.h_button - 8 while True: d = ui.measure_string(button.title,font=(button.font[0],font_size))[0]+4 if d <= wb: break font_size = font_size - 1 button.font = (button.font[0],font_size) x = x + wb + dx self.height = y + self.h_button + dy @on_main_thread def AddButtonsToPythonistaKeyboard(pad=None): ev = editor._get_editor_tab().editorView() tv = ev.textView() #print(tv._get_objc_classname()) #print(dir(tv)) # create ui.View for InputAccessoryView above keyboard v = MyView(pad) # view above keyboard vo = ObjCInstance(v) # get ObjectiveC object of v retain_global(v) # see https://forum.omz-software.com/topic/4653/button-action-not-called-when-view-is-added-to-native-view tv.setInputAccessoryView_(vo) # attach accessory to textview tv.strfind = '' if __name__ == '__main__': AddButtonsToPythonistaKeyboard(pad=[{'key':'pair'}])
-
Wow above and beyond the call of duty thankyou!