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.
pythonista UI
-
import ui
from objc_util import *
import clipboard
import speechv = ui.View()
v.frame = (0,0,500,320)
v.name = 'Move cursor in TextView'tv = ui.TextView()
tv.name = 'TextView'
tv.frame = (120,10,370,300)
tv.font = ('Arial Rounded MT Bold',24)
tv.text = 'aé😢🇯🇵👨👨👧👧'
v.add_subview(tv)def say_char(tv):
# test speech character at cursor
idxtopos = IndexToPos('') # list index to position#print(c,nb,len(idxtopos)-1,i,x) idxtopos.append(i+1) # end position of last c #print(idxtopos) # get index of actual cursor i = tv.selected_range[0] # actual position of cursor # often p is one of sub_chars, not always the first one p = idxtopos[i] # used to check if same base character #print(p,i,idxtopos) if type == 'left': if i == 0: return # already before character while True: i = i - 1 if idxtopos[i] != p: q = idxtopos[i] # seach first sub-character while i > 0: if idxtopos[i-1] != q: break i = i - 1 break elif type == 'right': if i == (len(idxtopos)-1): return # already after last character while True: i = i + 1 if idxtopos[i] != p: break elif type == 'end': i = len(idxtopos)-1 else: return idxtopos r = idxtopos[i] say_char(i) return idxtopos
i = tv.selected_range[0]
#print(i,idxtopos)
i = idxtopos[i] # used to check if same base character
if i < len(tv.text):
c = tv.text[i]
if c == ' ':
c ='space'
speech.say(c,'jp-JP')```
def selected_range(i):
tvo = ObjCInstance(tv)
p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), i)
p2 = p1
tvo.selectedTextRange = tvo.textRangeFromPosition_toPosition_(p1, p2)
returnsome emoji like flags count as 2 for len but as 4 for selected_range
def IndexToPos(type):
tvo = ObjCInstance(tv)
# build array index -> position in range
idxtopos = []
pre_x = -1
#print(tv.text)
for c in tv.text:
# nbr characters used e=1 é=1 😂=1 🇯🇵=2 👨👨👧👧=7
# some emoji generate more than one character,
# sometimes counted for more than one in range
# 1,2,3->1 4->2
nb = 1 + int(len(c.encode('utf-8'))/4)
for j in range(0,nb):
p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), len(idxtopos))
p2 = p1
rge = tvo.textRangeFromPosition_toPosition_(p1, p2)
rect = tvo.firstRectForRange_(rge) # CGRect
x = rect.origin.x
if x == float('inf') or x == pre_x:
# same x as previous one, composed character
pass
else:
pre_x = x
i = len(idxtopos)
idxtopos.append(i) # start position of c```
Insert Code Here -
I'm sorry.
I'm not sure how to send this code.
The change of the code has already finished, but there is no change.I'm confused.
-
@shinya.ta Sorry but not readable, que you sure you use this
-
@shinya.ta hère is my entire code
import ui from objc_util import * import clipboard import speech v = ui.View() v.frame = (0,0,500,320) v.name = 'Move cursor in TextView' tv = ui.TextView() tv.name = 'TextView' tv.frame = (120,10,370,300) tv.font = ('Arial Rounded MT Bold',24) tv.text = 'aé😢🇯🇵👨👨👧👧' v.add_subview(tv) def say_char(tv): # test speech character at cursor idxtopos = IndexToPos('') # list index to position i = tv.selected_range[0] #print(i,idxtopos) i = idxtopos[i] # used to check if same base character if i < len(tv.text): c = tv.text[i] if c == ' ': c ='space' speech.say(c,'jp-JP') def selected_range(i): tvo = ObjCInstance(tv) p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), i) p2 = p1 tvo.selectedTextRange = tvo.textRangeFromPosition_toPosition_(p1, p2) say_char(tv) return # some emoji like flags count as 2 for len but as 4 for selected_range def IndexToPos(type): tvo = ObjCInstance(tv) # build array index -> position in range idxtopos = [] pre_x = -1 #print(tv.text) for c in tv.text: # nbr characters used e=1 é=1 😂=1 🇯🇵=2 👨👨👧👧=7 # some emoji generate more than one character, # sometimes counted for more than one in range # 1,2,3->1 4->2 nb = 1 + int(len(c.encode('utf-8'))/4) for j in range(0,nb): p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), len(idxtopos)) p2 = p1 rge = tvo.textRangeFromPosition_toPosition_(p1, p2) rect = tvo.firstRectForRange_(rge) # CGRect x = rect.origin.x if x == float('inf') or x == pre_x: # same x as previous one, composed character pass else: pre_x = x i = len(idxtopos) idxtopos.append(i) # start position of c #print(c,nb,len(idxtopos)-1,i,x) idxtopos.append(i+1) # end position of last c #print(idxtopos) # get index of actual cursor i = tv.selected_range[0] # actual position of cursor # often p is one of sub_chars, not always the first one p = idxtopos[i] # used to check if same base character #print(p,i,idxtopos) if type == 'left': if i == 0: return # already before character while True: i = i - 1 if idxtopos[i] != p: q = idxtopos[i] # seach first sub-character while i > 0: if idxtopos[i-1] != q: break i = i - 1 break elif type == 'right': if i == (len(idxtopos)-1): return # already after last character while True: i = i + 1 if idxtopos[i] != p: break elif type == 'end': i = len(idxtopos)-1 else: return idxtopos r = idxtopos[i] selected_range(i) return idxtopos b_top = ui.Button() b_top.frame = (10,10,100,32) b_top.title = 'begin' b_top.background_color = 'white' b_top.border_width = 1 def b_top_action(sender): tv = sender.superview['TextView'] tv.selected_range = (0,0) say_char(tv) b_top.action = b_top_action v.add_subview(b_top) b_left = ui.Button() b_left.frame = (10,50,100,32) b_left.title = 'left' b_left.background_color = 'white' b_left.border_width = 1 def b_left_action(sender): idxtopos = IndexToPos('left') # list index to position b_left.action = b_left_action v.add_subview(b_left) b_right = ui.Button() b_right.frame = (10,90,100,32) b_right.title = 'right' b_right.background_color = 'white' b_right.border_width = 1 def b_right_action(sender): idxtopos = IndexToPos('right') # list index to position b_right.action = b_right_action v.add_subview(b_right) b_bottom = ui.Button() b_bottom.frame = (10,130,100,32) b_bottom.title = 'end' b_bottom.background_color = 'white' b_bottom.border_width = 1 def b_bottom_action(sender): idxtopos = IndexToPos('end') # list index to position b_bottom.action = b_bottom_action v.add_subview(b_bottom) def get_xy(tv): idxtopos = IndexToPos('') # list index to position tvo = ObjCInstance(tv) x_y = [] for i in range(0,len(idxtopos)+1): # x,y of each character p1 = tvo.positionFromPosition_offset_(tvo.beginningOfDocument(), i) rge = tvo.textRangeFromPosition_toPosition_(p1,p1) rect = tvo.firstRectForRange_(rge) # CGRect x,y = rect.origin.x,rect.origin.y if i == len(idxtopos): if i > 0: x,y = x_y[i-1] else: # text is empty x,y = 0,0 if x == float('inf'): x,y = x_prec+15,y_prec x_prec,y_prec = x,y x_y.append((x,y)) return x_y b_up = ui.Button() b_up.frame = (10,170,100,32) b_up.title = 'up' b_up.background_color = 'white' b_up.border_width = 1 def b_up_action(sender): tv = sender.superview['TextView'] x_y = get_xy(tv) c = tv.selected_range[0] xc,yc = x_y[c] i = c - 1 while i >= 0: x,y = x_y[i] if y < yc: # previous row if x <= xc: selected_range(i) return i = i - 1 b_up.action = b_up_action v.add_subview(b_up) b_down = ui.Button() b_down.frame = (10,210,100,32) b_down.title = 'down' b_down.background_color = 'white' b_down.border_width = 1 def b_down_action(sender): tv = sender.superview['TextView'] idxtopos = IndexToPos('') # list index to position x_y = get_xy(tv) c = tv.selected_range[0] #print(x_y,c) xc,yc = x_y[c] i = c# - 1 # I don't remember why this "- 1" while i < len(idxtopos): x,y = x_y[i] if y > yc: # next row if x >= xc: selected_range(i) return else: if (i+1) < len(idxtopos): if x_y[i+1][1] > y: # i = last character of row under cursor selected_range(i) return else: pass # try next x else: # last character of last row selected_range(i) return i = i + 1 b_down.action = b_down_action v.add_subview(b_down) b_copy = ui.Button() b_copy.frame = (10,250,100,32) b_copy.title = 'copy' b_copy.background_color = 'white' b_copy.border_width = 1 def b_copy_action(sender): tv = sender.superview['TextView'] clipboard.set(tv.text) b_copy.action = b_copy_action v.add_subview(b_copy) b_clear = ui.Button() b_clear.frame = (10,290,100,32) b_clear.title = 'clear' b_clear.background_color = 'white' b_clear.border_width = 1 def b_clear_action(sender): tv = sender.superview['TextView'] tv.text = '' b_clear.action = b_clear_action v.add_subview(b_clear) v.present('sheet') tv.selected_range = (0,0) tv.begin_editing()```
-
It's done.
I misunderstood the code I changed.
Thank you very much.
Thank you very much.I had tears.
You are really my God.
-
@shinya.ta 😭 --> 😂
-
@shinya.ta I suppose your setting Settings -> General -> Accessibility -> Speech -> Speak Selection and check if the ON/OFF switch is green (active) is ON
In this case, if you try to select all your text, you'll see a speak option, try it and all letters and emoji are read aloud. It is perhaps possible to use objectivec code instead of the Pythonista speech to read so.
Try Spell also, marvelous
-
I did not know that there is such a wonderful function.
I am working now, so I will try it when I go home.
Thank you for your wonderful advice.
After all, you are God.
-
-
This time, I added the following code.
I selected the emoji I read aloud and put it in the task bar.
When the Text View is blank, when you press the cursor move button, there is an error.
What's the cause?
#絵文字タスクバー
def typeChar(sender):
'''finds active textinput, and types the button's title'''
tf=sender.objc_instance.firstResponder()
tf.insertText_(sender.title)#create normal keys
buttons=[]
for button_title in '😊😜😱💦☔️':
buttons.append(ui.Button(title=button_title,action=typeChar))#create special keys
def prev(sender):
'''simulates 'tab' key, go to next field '''
s=sender.objc_instance.firstResponder()._previousKeyResponder().becomeFirstResponder()
buttons.append(ui.Button(image=ui.Image.named('iob:ios7_arrow_back_32'),action=prev))def next(sender):
'''simulates 'tab' key, go to next field '''
s=sender.objc_instance.firstResponder()._nextKeyResponder().becomeFirstResponder()
buttons.append(ui.Button(image=ui.Image.named('iob:ios7_arrow_forward_32'),action=next))'''set up toolbar'''
keyboardToolbar=ObjCClass('UIToolbar').alloc().init()
keyboardToolbar.sizeToFit()
keyboardToolbar.items = [ObjCClass('UIBarButtonItem').alloc().initWithCustomView_(b) for b in buttons]#attach our accessory to the textfield, and textview.
tv.objc_instance.setInputAccessoryView_(keyboardToolbar)v.present('sheet')
tv.selected_range = (0,0)
tv.begin_editing() -
@shinya.ta Is she able to select the text and to tap the spell button?
-
I think training is necessary, but I think it's possible.
-
@shinya.ta add "i = 0" before "for c..." in "def IndexToPos..." as here-under
def IndexToPos(type): tvo = ObjCInstance(tv) # build array index -> position in range idxtopos = [] pre_x = -1 #print(tv.text) i = 0 for c in tv.text:```
-
Thank you very much.
We were able to solve it immediately.
There is a "◀︎▶︎" in the task bar, so I don't think that's necessary.
I'm trying to remove it, but I'm not sure which one I should turn off. -
I want to increase the type of emoji in the task bar, but when I try to increase the number of emoji, the original emoji will hide and I can't display them.
-
@shinya.ta Try this
#create special keys def prev(sender): '''simulates 'tab' key, go to next field ''' s=sender.objc_instance.firstResponder()._previousKeyResponder().becomeFirstResponder() buttons.append(ui.Button(image=ui.Image.named('iob:ios7_arrow_back_32'),action=prev)) def next(sender): '''simulates 'tab' key, go to next field ''' s=sender.objc_instance.firstResponder()._nextKeyResponder().becomeFirstResponder() buttons.append(ui.Button(image=ui.Image.named('iob:ios7_arrow_forward_32'),action=next)) #create normal keys d = 32 dd = 4 w, h = ui.get_screen_size() vv = ui.View() vv.background_color = 'lightgray' h = 0 x = dd y = dd for button_title in '😊😜😱💦☔️😀😃😄😁😆😅😂🤣☺️😊😇🙂🙃😉😌😍🥰😘😗😙😚😋😛😝😜🤪🤨🧐🤓😎🤩🥳😏😒😞😔😟😕🙁☹️😣😖😫😩🥺😢😭😤😠😡🤬🤯😳🥵🥶😱😨😰😥😓🤗🤔🤭🤫🤥😶😐😑😬😦😧😮😲😴🤤😪😵🤐🥴🤢🤮🤧😷🤒🤕🤑🤠😈': b = ui.Button(title=button_title,action=typeChar) b.frame = (x,y,d,d) b.font = ('.SFUIText', d) if (y+d+dd) > h: h = y + d + dd vv.add_subview(b) x = x + d + dd if (x+d+dd) > w: x = dd y = y + d + dd vv.frame = (0,0,w,h) #attach our accessory to the textfield, and textview. tvo = tv.objc_instance tvo.setInputAccessoryView_(ObjCInstance(vv)) v.present('sheet') tv.selected_range = (0,0) tv.begin_editing()
-
-
@shinya.ta you are sure you have not removed your
def typeChar(sender): '''finds active textinput, and types the button's title''' tf=sender.objc_instance.firstResponder() tf.insertText_(sender.title)
-
It was successful.
By using this task bar, I think my wife can write a message happily.
Thank you very much.
-
@shinya.ta You could even add your "own" buttons in this taskbar...