Forum Archive

Programmable keys in Pythonista for quickly wrench actions execution

Matteo

Hi, I open a new topic for a request that could be useful: wrench actions are a great feature of Pythonista for both Text Editor and File Browser (thank you @dgelessus for hint about wrench on File Browser!) but they are only accessible via the key/icon wrench at top-right of Text Editor and at bottom right of File Browser after touch Edit.

Could be more convenient to have:
1. for Text Editor, a keys bar above the one with the text symbols (punctuation, brackets, ...) that can be hidden/shown by user with the wrench key/icon instead of to have a new window with inside all the built-in and user-defined wrench actions (the current feature)? The keys (10 keys) are little but if we could personalize the icons, user could recognize them without text description (user should memorize the actions with icons).
Furthermore the keys could be added or removed and associate to them different actions or modified by the user, as it is now but without opening new windows that prevent the user from modifying the code if he did not close the wrench window before, ie remaining in the environment Text Editor?
2. for File Browser, the user defined keys bar could be placed above the bar with the keys +, °°° and Setting-icon and it could be hidden or showed touching the Edit key at top-right and after selecting some folder or files.

I'd like to know your ideas/comments
Thanks
Bye

JonB

That was sort of the point of an old program called editmenu.
older pythonista versions offered a handy sidebar presentation style, and we used this for little quick icons. I think someone recently rewrote this to work for new pythonistaversions, but I cant find that thread right now.

On ipad, you can add buttons to the main toolbar, via objc.
See apphack.py in my objc_hacks repo.
https://github.com/jsbain/objc_hacks.git

Matteo

@JonB Thank you for help, I've tried your apphack.py and it works well! This idea is what I have in my mind and inspired by your work, I'd like to create a pythonista_startup.py script that realizes the idea.

I don't know if the position of keys could be updated based on screen orientation (portrait or landscape).

I don't know anything about objc_util and I ask you if I can find something to study about it. But before to start studying a new thing, I prefer to know if keys idea in the link is possibile with current Pythonista version.
In general, which areas of Pythonista windows could be programmed and personalized by user? Only top bar of text editor?

And, sorry for this, how can I add an action (as a simple example, touching the key I'd like to select all text in the editor and copy it in clipboard) to the key in your script apphack.py?

Thank you
Bye

JonB

So, I am not that familiar with pythonsta on the iphone -- apphack pribably diesnt work well on small screens.

Another option might be a custom inputaccessoryView. Will play around with it.

Matteo

@JonB Hi, could you kindly tell me where, in your code apphack.py, I can add actions to the user key? I'd like to perform some tests with very simple actions like select all text or move the cursor in a specific position in the text showed in editor.

Thank you very much,

Bye

JonB

create_toolbar_button(action,image,index=0,tag='')

here is a more complete example
https://gist.github.com/f380efe40155f9360da588a5d73661be

Matteo

@JonB Hi, ok, it is a good and well explained starting point to begin user keys programming. Thank you for sharing it. I will perform some tests with your scripts in order to try to create a user keys bar with different actions.
Pythonista is full of surprises!

Regards
Bye

Matteo

@JonB Hi! First of all thank you for your scripts about user keys.

I'd like to create an user key that hides the built-in key at the left as in image below:

link text

How can I change the numbers in apphack.py in order to obtain what you can see in image?

This because in my little screen the only area that can be customized is the key with the three horizontal lines. My user key (main user key) will appear every time Pythonista is restarted.
If I touch the main user key, it will show some other keys from it to the built-in run key.
If I re-touch the main user key, it will hide the user keys previously visible, in order to use built-in keys (previously hidden).

I ask you also if user keys can disable the touching functioning of built-in keys (that is: when I create an user key that is up/above a built-in key and I touch my user key, I‘d like to avoid to touch also the built-in key; sometimes it happens ).

Thank you,
Regards

JonB

It should be possible to override the app's menu button, to either install our own button press action, or longPress, or even swipe, etc. Ill play around with some ideas

Matteo

@JonB Good, it would be a very useful thing in my opinion to be able to program own keys that could replace some built-in keys without interfering with them (by touching an user key that is at the same position of a built-in key, user should run only the action related to the user key, avoiding to touch accidentally the built-in key in the lower "layer").

The built-in key at the left of image above (inside the circle) performs the same task of sliding from left to right the screen in order to show the file browser window from the text editor page. As this action is available also with sliding gesture, that key could be hidden by an user key that could show or hide (touching it and re-touching it) own personal keys based on user needs.

Thank you for your time. For now, I ask you if I can show my user key in the left side of iphone screen. Do I must change the values

...
tb.rightItemsWidth()-(index+1)*40,0,30,40
...

?
Bye

JonB

If you want to add buttons starting on the left:
btn=ui.Button( frame=((index)*40,22,40,40))

Or, just increase the index large enough to go where you want.

One problem may be that parts of the toolbar get rebuilt when switching tabs. So, your button could end up underneath the default, but I'm not sure.
I did implement a swipe gesture on the built in wrench (i.e swipe down pops up a quick shortcut menu) but because the button keeps getting reset, this doesn't stick.
This also seems to be the issue with trying to customize the coming keyboard, as it seems to get rebuilt dynamically.

cvp

@Matteo You could execute this code after

tb=get_toolbar(main_view)

to remove (definitely) the left button (x=8.0 on my iPad, to be tried on iPhone).
But to retrieve it, you'll need to restart Pythonista (I guess)..
Correction: button comes back when Pythonista is back in foreground
for v in tb.subviews(): if v._get_objc_classname().startswith(b'OMBarButton'): print(v.indexInSuperview(),v.frame().origin.x) # just to be sure if v.frame().origin.x == 8.0: v.removeFromSuperview()

Matteo

Thank you @JonB and @cvp for help! I performed some tests and you can see the output in images below:

First:
link text

Second (after touching Pythonista Run button):
link text

Third (after touching the user button at left):
link text

Fourth (after touching the long bar):
link text

In the last image it seems that the long bar (that is a series of little squares) doesn't work properly because when I touch it, the action is the same user obtains when touches the filename of the script (it shows the list of definitions in the current script).
The last button , at the right, works properly (it hides in a good way the built-in wrench button) and touching it, the action prints 'hello' in the console as expected (it is a very very simple test).

Have you some ideas why the long bar can't hide the built-in button (that is the filename of the current script) as the single button at the right?

If you need to test the code I will post here a link.

Thanks
Regards

cvp

@Matteo I had also remarked that the "file name button" has priority, but no idea why.

Matteo

@cvp Hi, ok, it's strange because the top bar should be entirely programmed with user keys.
Maybe the field where there is the script name is reserved or it is so big that even if I touch the long bar, I accidentally touch the built-in filename button.

Do you know if we can increase the size of user buttons? I will try to increase the width of the long bar in order to see if I can hide completely the built-in button of the script name.

Thanks
Regards

cvp

@Matteo

Matteo

@cvp Hi, sorry but I can't use your hint to increase the width/hight of my user key (I most likely ignore something).

What I'd like to do is to create a button larger/higher than the one user can add searching in icons database "Images" (where user finds a lot of images for buttons, like Ionicons Black, Ionicons White, Planet Cute, Platformer Art, etc...). I already use the larger built-in icons (256 instead of 24 or 32) but I'm trying to increase more and more the button (more than 0.45 mm of height), in order to hide entirely the area of the screen from button |+| to button |> (I want to hide also ios wifi icon and current time above the long bar in image Third of my previous post). For now I'm interested only about portrait use of iPhone (that is the fastest way for me to run scripts with one hand when I'm away from home).

I don't know if the new big long bar will work, preventing me from accidentally touching of the filename built-in button (Anyway, I doubt I can succeed because it seems that the button dimension does not affect the Pythonista built-in filename button). But I will try if I know how to increase the size of buttons.

And an other question: how can you add text to user buttons or change background colour of them in order to have several buttons with different colours and different text inside to recognize them and their actions easly?

Thank you
Bye

cvp

@Matteo What you call "my hint" is only change the apphack.py code to set x and with of button.

btn=ui.Button( frame=(tb.size().width - tb.rightItemsWidth()-(index+1)*40,22,40,40))
Becomes 
btn=ui.Button( frame=(tb.size().width - tb.rightItemsWidth()-(index+1)*40-20,22,60,40))
cvp

@Matteo text, its color and border are set by

    btn.title = 'laaarge'
    btn.tint_color = 'white'
    btn.border_width = 1 
    btn.background_color = 'blue'
JonB

An option for keeping user buttons on top is

tb.superview().addSubview_(btn)

at the end of create_toolbar_button

cvp

@JonB btn or btn_obj?

cvp

@JonB I need to go up twice...

    tb.superview().superview().addSubview_(btn_obj)
Matteo

@JonB Wonderful, it works! I used the code:

tb.superview().superview().addSubview_(btn_obj)

(Thanks @cvp)

Really, @JonB how can you know these things? However, now I have a code that creates, every time I launch Pythonista, two buttons, at left and at right of upper bar. The left one, if touched, shows six little squares buttons (one button for one action). The right one, if touched, hides the six buttons.
Maybe you will find this a little easy, but for me it is a great thing ;-)

Two questions:
1. How can I program the left button in order to use it both for showing and hiding of the six user buttons? I mean, when the six buttons are showed, touching the left button should hide them; when the six buttons are hidden, touching the left button should show them.
2. Can Pythonista execute automatically a script every time user changes iphone screen from portrait to landscape and viceversa? Inside 'pythonista_startup.py'?

@cvp thank you for info about buttons size. But the last two values in:

btn=ui.Button( frame=((index)*40,22,40,40))

are a bit strange for me: what do they mean (40 and 40)?
And I can't show any text inside my buttons. Can you kindly show me what and where I must add some code for button text? Let's imagine the user button must show the text "Copy": what should I do in the following code (JonB's apphack.py) to add text inside the button?

# coding: utf-8
''' A set of tools to add or delete custom buttons from the toolbar.  This may not be super robust, but seems to work ok.  Button objects and actions are saved so they survive global clearing, but thid has not been tested extensively.  If a function relies on imports that occured outside of the function, these might dissappear -- user must make sure those modules are added to a module that is kept by pythonista, such as anything in site-packages, or name starting with __   '''

from objc_util import *
import ui,console
import weakref
from functools import partial



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 create_toolbar_button(action,image,index=0,tag=''):
  '''create a button on main toolbar, with action, imagename, index location, and string tagname.  button and action are stored in __persistent_views[index]. tag allows finding view using tb.viewFromTag_(hash(tag)) (old idea)'''
  assert(callable(action))

  tb=get_toolbar(main_view)

  global __persistent_views
  try:
    __persistent_views
  except NameError:
    __persistent_views={}
  #check for existing button in this index and delete if needed
  remove_toolbar_button(index)

  #add new button to the left of the rightbuttons.  index 0 is next to left buttons, index 1 is further left, etc
  #store so it is not cleared.
  btn=ui.Button( frame=((index)*40,22,40,40))

  btn.flex='L'
  btn.image=ui.Image.named(image)
  btn.action=action
  btn_obj=ObjCInstance(btn)
  btn_obj.tag=hash(tag)

  __persistent_views[index]=(btn,action,tag)
  tb.addSubview_(btn_obj)

  #JonB suggestion:
  tb.superview().superview().addSubview_(btn_obj)


  return btn



def remove_toolbar_button(index):
  global __persistent_views
  try:
    btn,action,tag=__persistent_views.pop(index)
    btn.action= None
    ObjCInstance(btn).removeFromSuperview()
  except KeyError:
    pass



if __name__=='__main__':
  def run_script(sender):
    '''run a script without clearing glbals'''
    import editor
    exec(editor.get_text(),globals())
    remove_toolbar_button(0)


  create_toolbar_button(run_script,'iow:stop_256',0,'execfile')

Thank you so much!
Regards

cvp

@Matteo
1) .....,40,40) = width and height of the button
Edit: if you add a text like 'copy' you could need to set a bigger width and no image
2) as explained in one of my previous posts, you can set the text, its color, etc...

btn.image = ...
btn.title = 'copy'
btn.action = ...
cvp

@Matteo If your actual
left button does

btn1.hidden = True 

right button does

btn1.hidden = False

Your future unique button could do

btn1.hidden = not btn1.hidden
JonB

@Matteo We would have to experiment, but a custom view class layout method, would get called upon rotation, assuming flex=`w'.

JonB

https://gist.github.com/37e5115840bef9b898dba36ba3df5802

Here is an experiment, where I add a half-button at the top right corner of the screen (at battery icon), in the status bar. Tapping there pops down a menu. Tapping again makes it dissappear. You could adjust the size of this as desired. This seems somewhat cleaner, visually. At 32 height, buttons are tappable, and also could stay displayed without interfering with normal ui buttons. Things stay anchored correctly even with rotation.

This lives in the statusbar window, so is over top of everything, which might not be desirable... it might make more sense to keep the button in the statusbar, but keep the overlay in the editor, though this way, it is available even in console. You also have the whole screen to work with, if you want, so are not confined to the toolbar.

cvp

@JonB Whaaaaaaa, as usual

Matteo

@JonB Impressive, really! Thank you! I still find hard to believe that you can do certain things with Pythonista.
I tried your script in my iPhone 4'' screen and works very well.
I've seen that the user buttons remain in the three Pythonista windows: file editor, text editor and python console. It is a wonderful thing in my opinion: in this way user can have quickly access to favourite actions in file editor window (for actions an files and folders) and in text editor window (for actions on text and strings).

Your code is a little incomprehensible to me but I will try to adapt your work in order to use it with my frequent actions.
Thank you @JonB and @cvp for all help!
Regards

Matteo

@JonB Hi! Sorry but I can't solve a little problem with your code.

The procedure I follow to reproduce the issue is:

  1. full restart of Pythonista,
  2. run your script in order to show the half button in right up corner,
  3. write a simple python script like print('hello'),
  4. execute the script with |> button (it automatically goes to console window),
  5. return to text editor windows and touch the half button,
  6. it return NameError: global name 'ui' is not defined.

Note that the user buttons in action bar work well: if I touch for example the button 'Blah' it print in console the number 50.0. The problem is that I can't anymore hide the full action bar.

When you have time, can you kindly test the issue? Thank you very much,

Regards

PS: I use Pythonista 3.1 (301016).

cvp

@Matteo put the import ui in the action def...

JonB

Right, your actions have to stand alone, and cannot rely on globals, or external imports. All imports must happen in the def itself. That's because globals and modules get cleared.

cvp

@JonB Why did __persistent_views not disappear?

Matteo

@cvp Thank you! Solved adding

import ui

after

def toggleBar(self,sender):

Thank you both!

cvp

@Matteo Really, @JonB did all the work, it was described in his comment at begin of script
''' A set of tools to add or delete custom buttons from the toolbar. This may not be super robust, but seems to work ok. Button objects and actions are saved so they survive global clearing, but thid has not been tested extensively. If a function relies on imports that occured outside of the function, these might dissappear -- user must make sure those modules are added to a module that is kept by pythonista, such as anything in site-packages, or name starting with __ '''

JonB

@cvp variables with double underscores don't get cleared when running a script. Nor do modules in site-packages, modules starting with dunders, and a few other rules which I can never remember (you can look at pythonista_preflight.py)

cvp

@JonB Ok, understood, thanks. But, in this case, why to set this variable as global?

Matteo

@cvp Yes you are right, I've tried to read JonB string at the beginning, but I don't have great programming knowledge so, when I read, lets say, 100 words about programming, I understand, the first time, about 20-30 %.
Anyway I will try to work with JonB script, that in my opinion gives to Pythonista much power for little screens (I repeat that Wrench action window of Pythonista is a wonderful feature, but in my little screen its window hides all my screen preventing me to see my code in text editor window).

Regards
Bye

cvp

@Matteo No problem, my post was only to say that all comes from @JonB, really not from me.
I only read his code. I'm like you, I don't understand all 😢

cvp

@JonB Sorry, I feel very very little/bad/novice/zero (delete eventual useless adjectives, if any) but even that I can't 😢: I don't find this Pythonista_preflight?py

dgelessus

@cvp It's an internal script used by Pythonista, you can't find it anywhere in Pythonista's file browser. You can open it using the editor module though:

import editor
import os

py3kit_dir = os.path.dirname(os.path.dirname(os.__file__))
editor.open_file(os.path.join(py3kit_dir, "pykit_preflight.py"))
cvp

@dgelessus Thanks, but I searched for pythonista_preflight.py 😢

cvp

@dgelessus & @JonB Thanks to both to help me to learn each day something's new.

dgelessus

It's the same script - in older versions it was called pythonista_preflight.py, then it was renamed to pykit_preflight.py. I think @JonB was just using the old name.

cvp

@dgelessus Thanks

JonB

By the way, here are my notes on ways to keep variables/modules from getting cleared by preflight:

ways to keep modules from clearing:

1) for modules, delete __file__
e.g

   import mymodule
   del mymodule.__file__

now mymodule is not removed from sys.modules
2) create name staring with dunder__

   import mymodule
   sys.modules['__mymodule']=sys.modules['mymodule']

3) set file access to nonwritable

   chmod(mymodule.__file__,0xo444)

4) place module in site-packages

ways to keep global vars from being cleared

1) start variable with __

     __myglobalvar=4

2) add to pythonista_startup

     myglobalvar=4
     import pythonista_startup
     pythonista_startup.myglobalvar=myglobalvar

for things like ui.Views, threads, which needs to reference itself, but does not need to be refernced externally, etc it is sufficient to simply add the var to an existing builtin module

    try:
       ui.mysavedviews.append(myview)
    except NameError:
        ui.mysavedviews=[myview]

retain_global is another way.

Matteo

@JonB Thank you for these advanced info.

About your code, I've tried to understand how to add an extra horizontal bar with extra six buttons under the default bar.

In this example the extra bar under the main one will hide the filename , the run button |≥ and some other built-in keys. But this is not a problem because user can hide the two bars with one touch on the half button in high corner in order to use run key or others.

The target is to have about 10/12 user keys that , when visible, hide the entire height of Pythonista bar.
Unfortunately I can't create this extra bar under the one you see in image.

As always, I ask you if you have time how I can modify your code to add an extra bar with extra 6 buttons.

Thank you again
Regards

Matteo

Hi! The empirical approach always helps (almost always indeed). After some tests with some changing of numeric values and adding some extra code (copying/modifying some JonB's pieces of code of his Great script) the output is the following (images below).

First (file browser):

Second (console):

I wait to post the full code (that is the JonB's code slightly modified) because I have a little problem with screen rotation: from portrait to landscape and from landscape to portrait the two bars can't return to default one (you can see the problem in image below: the bars become very large...):

I will try to solve this bug that I've introduced modifying the JonB's script and if I will find a solution I will post here the full code, that you can personalize with icons and actions (I can't insert text in background under the buttons/icons ... It would be useful for whose like me can't remember the action of each button/icon without any keyword like, for example, 'find in files' or 'on/off' word wrap).

Regards

JonB

fwiw, in my previous version you can include a title and image, or could include both. Maybe a more useful approach would be either a help icon, which when active replaces all actions with a hud alert with the name, or, long press gestures that do the same. We could also do something where really tiny text is added to the image icon.

How do you want rotation to behave? Resize the bar and reorganize (fit on one line if there is room)? Or still show two row bar?
I would recommend a single bar, set to the size you want, with set to only flex='L' . You would size it manually, to fit portrait. The add action would then not do any resizing, but would need to keep track of how many buttons have been added, and start adding to the second row. or just accept a row parameter.

Matteo

Hi @JonB sorry for delay, thank you for your answer! Yes, you are right about text , but in little screens, text near buttons is space consuming: in little screens , as you already told me in your last post, it would be useful to have tiny text inside buttons (black text on blue buttons should be well visible). Maybe text with maximum 5/6 letters, but I don't know if it would be visible.

About my bug, this weekend I will try to have the same effect I have with your code when I change screen from portrait to landscape: I like when, with your code, the bar disappears in landscape mode and appears again when in portrait mode. With the code modified by me in order to add an extra bar for extra 6 buttons, the script works well but after changing screen mode from portrait to landscape and to portrait again, the two bars in my modified code can't be resized as after the first run of the script.

I will try to debug the code to have two working bars in portrait, even if I change accidentally the screen rotation of phone.

Sorry for my poor answer now but next weekend I will have some time to spend with Python!

Thank you
Regards
Bye

Matteo

Hi @JonB , I've solved partially my problem.
Now the script resizes correctly the two bars when I return to portrait mode from landscape. I've modified

self.overlay.flex = 'lwh'

in

self.overlay.flex = 'l'

The problem now is that the two bars are visible also in landscape mode but I can't hide them because the triangle button that shows-hides the bars is invisible (out of screen) when in landscape mode.

My questions:
1. how can I modify this code (your code slightly modified with an empirical approach, ie without knowing what I'm doing ;-)) in order to hide the two bars when my phone is in landscape mode? If the two bars are visible in portrait mode and I change in landscape mode, the two bars should disappear and if I return in portrait mode they should be visible again.
2. How can I change the shape (geometric polygon) and position (x, y) of the half-button at the top right corner of the screen in order to show it also in landscape mode? In other words, why it disappear when in landscape mode?

Thank you for help
Regards

Matteo

Hi @JonB, I explain also (I had forgotten to do it in last post) the text-on-icons idea (is it what you have in mind?) with the image below:

The image you see is made with a very simple image editor software in pc.

But if you could make it possible to insert text in the foreground on the buttons in your script like in the image, in addition to understanding how to hide the two button bars in landscape mode it would be very useful.

As always, only if you have time to spend on it and if it suits your interest.
Thank you
Regards

cvp

@Matteo You could play, instead of btn.image, with btn.background_image and btn.title

cvp

@Matteo Or you could design your own icons with eventual text

cvp

@Matteo Or, better, I think, you could add a label on the button with
lbl = ui.Label() lbl.frame = (0,0,btn.width,btn.height) lbl.text = 'copy' btn.add_subview(lbl)

cvp

@Matteo see

Matteo

Hi @cvp, thank you for your help! Unfortunately I need to add text like in last image I've posted in the @JonB script, and even if I understand something about your piece of code, I don't know where and how to implement it in JonB script (I have no skills about it). If you kindly could show me some hint on how to add text, like in image, inside one single button in the script at point 1 of post number 51 , it would be more easy for me to do that for all my personal buttons.

Really sorry if I ask a full working script starting by an existing one, but it is the only way I can learn something deep about Pythonista (and sometimes I'm a little lazy).

Anyway I will try again to implement your code in JonB script.
Regards

cvp

@Matteo
Try this but text can't be long because button is little
Do not use passed title as button title but as label text

      b=ui.Button(title=None,image=image,action=action)
      b.size_to_fit()
      self.overlay1.add_subview(b)
      lbl = ui.Label()
      lbl.frame = (0,0,b.width,b.height)
      lbl.font = ('<System-Bold>',16)
      lbl.text = title
      b.add_subview(lbl)    

And

__s.add_action1(a,'txt',ui.Image.named('iow:arrow_resize_32'))
Matteo

@cvp You are right, it works! The trick is to change

b=ui.Button(title=title,image=image,action=action)

in

b=ui.Button(title=None,image=image,action=action)

Thank you!
Regards

Matteo

Hi guys! Only to say that I've understood (by trying several times and by searching in Internet) how to hide the two bars when in landscape:

self.overlay1.flex='t'
self.overlay2.flex='t'

Sorry if for you all is easy, but it was not very easy for me ;-) For example I ask myself "what does 't' mean instead of 'l' in flex?"

Now I have a full working script (thanks again to @JonB and @cvp for great support about user buttons request) that I think is good enough for iPhone 5s! I'm happy because I've obtained what was my target!

Here the script.

Thank you all,
Regards

JonB

Flex tells you what happens when the containing view is resized. The way to envision things are springs or bars connecting the top, left, right and bottom of the view to the corrrsponding edge of the parent, and also a bar across (width) and vertical (height) of your view.

By "flexing" one of these, it becomes a spring.
So, for example, 'W' will allo the width to be flexible -- so keeps the same margin to the parent view by adjusting your view's size.
L means that the left side can float (anchors to the right)
LW means it is anchored to the right side, and the width is resized as the parent is resized.

Matteo

Hi @JonB, thank you for explanation, but in general where can I find documentation about flex and other similar advanced things in order to customize Pythonista IDE?
Thanks
Regards

JonB

Flex is somewhat documented in the you docs. The native version is called autoresizing masks, which you can do Google searches for.

The other approach that might work better for you is a custom view class that implements a layout method. Then, you can relayout the entire view when orientation changes, such as doing one long bar in landscape and two bars in portrait...

Matteo

@JonB Thank you for your answer, and yes, it is interesting to know that user could have a view "A" when in portrait and a view "B" when in landscape. I like your idea about having two short bars in portrait and a single long bar in landscape, obviously it makes sense for little idevices, no problem with ipads.

The only problem about having a single long bar in landscape mode is how to show the triangle key at up-right corner in landscape in order to hide/show the bar based on user choice.

My curiosity: in Pythonista how can user write some python code that executes an external script when in portrait and an other external script when in landscape (I mean, immediately after rotating the device in portrait or landscape mode?)

Thank you very much,
Regards

JonB

The original code ensured the right corner was aligned to the right side of the screen, then flex='L' kept it there.

Another option is a custom layout method, which would run code as you describe.

It is possible to write a notification handler to register for rotation events. in objc that looks like

[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRotate:)name:UIDeviceOrientationDidChangeNotification object:nil];

but in this case, the StatusBarOverlay would already get these events, so a method named layout would get called automatically, so i wouldnt go that complexity (have to create an objclass, objcinstance, and manage its lifetime)

Matteo

@JonB Hi, thank you, I will try to write a script that executes script A when idevice is in portrait and script B when in landscape. But first of all I will need to study something about what you posted ;-)

I just finished to add a key action to the user buttons bars that executes any python script with the remote server provided by SageMathCell: now I have the 12th user key (last one of second bar, that is over the built-in Run key) that executes the opened script in editor with remote Sage interpreter, without need to open the big wrench window that freezes the entire editor (with it I can't scroll up/down, swipe, add new values in the script, etc...).

Question: how can I force Pythonista to switch automatically to Console window after the execution of any script? Purpose: I'd like to see always the output in Console of a script without manually swiping with finger from right to left. I noticed that the very first execution switches to Console and the next executions of the same script/action work well but can't switch automatically to Console.

Thank you
Regards

JonB

okay, here is a working version of a multiline toolbar, that adjusts as needed for orientation. If the buttons don't fit on one line, a second line is added. Not the cleanest code, but works.

I also showed some examples of using draw_string to add text within an existing icon, or custom icons.

def show_console(sender):
app.keyWindow().rootViewController().showAccessoryWithAnimationDuration_(1)

is an action you can use to show the console.

Matteo

Hi @JonB, thank you so much for your scripts!

The code:

app.keyWindow().rootViewController().showAccessoryWithAnimationDuration_(0.5)

works well in any user button created with original StatusBarOverlay by you and with the modified version for two bars in portrait mode.

About your new script I will try to inspect it and do some tests in order to create one long bar with 12 keys in landscape mode (with the right up corner key to show/hide the long bar).

An other idea in my mind about user keys is the creation of a key that executes the current script opened in editor but with a pre and post processing, that is: when touching that key, 1) it executes a script "pre.py" , 2) then executes the current main script opened in editor, and 3) finally executes a script "post.py". An usage example is : I want to execute only some parts of the opened script by preprocessing it and then creates automatically an animation of several images in a folder or creates a well formatted pdf of all variables of the main current script after its execution.
I will try to write a generic "recipe" to execute pre, main and post script, maybe next weekend, in order to have a second RUN button similar to the built-in one but with pre-post proc.

Thank you
Regards