How to refer the button node position (Instead of the selected node) in a script

33 views
Skip to first unread message

Fidel Pérez

unread,
May 25, 2013, 8:00:46 AM5/25/13
to leo-e...@googlegroups.com
Hi:
Im trying to make a button loop through all its siblings and make buttons of them when their bodies have certain conditions. This way, when I increase the tree, the button will auto-update with the new branches.

For that, I need to refer the actual button's sibilings, instead of the "node which is selected" when i press the button. I need "p" of the node when my position is in another node (to which I will have to refer too) so I actually get an interaction among the sibilings tree and the position Im currently in.

I have read the documentation and in the "import objects" section they refer everything but this. Any suggestions?

Thank you!

Terry Brown

unread,
May 25, 2013, 10:53:34 AM5/25/13
to leo-e...@googlegroups.com
On Sat, 25 May 2013 05:00:46 -0700 (PDT)
Fidel Pérez <fidel...@gmail.com> wrote:

> Hi:
> Im trying to make a button loop through all its siblings and make buttons
> of them when their bodies have certain conditions. This way, when I
> increase the tree, the button will auto-update with the new branches.
>
> For that, I need to refer the actual button's sibilings, instead of the
> "node which is selected" when i press the button. I need "p" of the node
> when my position is in another node (to which I will have to refer too) so
> I actually get an interaction among the sibilings tree and the position Im
> currently in.

This question may have come up recently, here it is
https://groups.google.com/forum/?fromgroups#!topic/leo-editor/K90m_aIiz9k
last message in that thread.

Another way would be, if you were creating the button from a script, to
include a reference to the position in the command.

from leo.plugins.mod_scripting import scriptingController
sc = scriptingController(c)

def my_cmd(c=c, v=p.v):
p = c.vnode2position(v)
g.es("Created from "+p.h)

b = sc.createIconButton(
'but',
command = my_cmd,
statusLine = 'Make buttons',
bg="light_blue"
)

- stores v, not p, p will break
- create button by clicking run-script, or by making this a @script
node
- change its headline, click button again, new headline reported

And here's the really hacky version which knows not only the node it
came from but the button it's fired from:

from leo.plugins.mod_scripting import scriptingController
sc = scriptingController(c)
data = {'clicks':0}
def my_cmd(c=c, v=p.v, data=data):
p = c.vnode2position(v)
g.es("Created from "+p.h)
data['clicks'] += 1
data['b'].button.setText(str(data['clicks']))

b = sc.createIconButton(
'zero',
command = my_cmd,
statusLine = 'Make buttons',
bg="light_blue"
)
data['b'] = b

- sc.createIconButton() returns a QWidgetAction, not a QPushButton,
hence the '.button' part.
- I guess this is a closure, with the surrounding @script node acting
as the scope for the closure's data ('data').

Cheers -Terry

Fidel Pérez

unread,
May 25, 2013, 10:58:11 AM5/25/13
to leo-e...@googlegroups.com
Very much appreciated, got more homework to study :)

Fidel Pérez

unread,
May 25, 2013, 11:56:03 AM5/25/13
to leo-e...@googlegroups.com
Im really sorry to need so much help, but could you please show me the code to remove a created button from another button?
How to access the "button list" to be able to remove it from an "external" script? Where did you get the .button.settext command? There is no such definition in LeoPlugins...
Thanks Terry

Terry Brown

unread,
May 25, 2013, 10:51:13 PM5/25/13
to leo-e...@googlegroups.com
On Sat, 25 May 2013 08:56:03 -0700 (PDT)
Fidel Pérez <fidel...@gmail.com> wrote:

> Im really sorry to need so much help, but could you please show me the code
> to remove a created button from another button?
> How to access the "button list" to be able to remove it from an "external"
> script? Where did you get the .button.settext command? There is no such
> definition in LeoPlugins...
> Thanks Terry

No problem - what you're trying to do isn't supported by the API as
designed, so you have to use the versatility of Python to sneak around
behind its back.

class leoIconBarButton is defined in
.../leo/core/LeoPyRef.leo#Code-->Qt
gui-->@file ../plugins/qtGui.py-->Frame and component classes...-->class leoQtFrame-->class qtIconBarClass-->add (qtIconBarClass)

and descends from QtGui.QWidgetAction. Code following the class
definition assigns the button ivar, it's a QPushButton, hence
the .setText().

So in the second version, the one using the data dict, you have the
leoIconBarButton injected into the scope of the button command, data['b'].
data['b'].parent() is the QToolBar containing all buttons, so you could
iterate the buttons that way, but I'm guessing your purpose could use a
"master" button which create and destroys the other. Removing can be
as data['b'].parent().remove(data['b']), removes itself, or perhaps

for i in data['other_buttons']:
data['b'].parent().remove(i)
data['other_buttons'] = []

The commands bound to the secondary buttons could have the same data
dict in their closure the same way, so all the buttons could know of
each other.

Let me know if you need something more specific.

Cheers -Terry

Fidel Pérez

unread,
May 26, 2013, 9:53:35 AM5/26/13
to leo-e...@googlegroups.com
Thank you very much Terry, it was very useful information, will be working on it the next weeks and like always keep my conclusions on the Leo interactive tutorial I am preparing.

Fidel Pérez

unread,
May 27, 2013, 4:01:37 AM5/27/13
to leo-e...@googlegroups.com
Hey:
The first problem im encountering is that the command wont erase the button!! hehe... This is what I have tried so far:

from leo.plugins.mod_scripting import scriptingController 
sc = scriptingController(c) 
data = {'clicks':0} 
def my_cmd(c=c, v=p.v, data=data): 
    p = c.vnode2position(v) 
    g.es("Created from "+p.h) 
    data['clicks'] += 1 
    data['b'].button.setText(str(data['clicks']))
    data['b'].parent().remove(data['b'])
    data['b'].button.parent().remove(data['b'])
    data['b'].button.parent().button.remove()
    data['b'].parent().remove(data['b'])
    data['b'].remove()

b = sc.createIconButton( 
    'zero', 
    command = my_cmd, 
    statusLine = 'Make buttons', 
    bg="ligt_blue" 


data['b'] = b 

And none of them will erase the button.

On your answer I understand that:
data['other_buttons'] will be a global variable (will be accessed from other buttons scripts).
To add the newly created buttons to that, would this be the code?
b=sc.createiconbutton(...)
data['other buttons']=data['other buttons'].append(b)

Last but least important, the value
bg="ligt_blue"
 Will not change the button color. Since im building this for an interactive Leo tutorial, I would say colors are important since they will make more visual (and easier to learn, since I will use same colors for same command types) for the new user.

Again very thankful, Im really eager to finish this and get to know your oppinions on this tutorial =)

Edward K. Ream

unread,
May 27, 2013, 8:56:08 AM5/27/13
to leo-editor
On Mon, May 27, 2013 at 3:01 AM, Fidel Pérez <fidel...@gmail.com> wrote:
Hey:
The first problem im encountering is that the command wont erase the button!!

Take a look at the deleteButton method in mod_scripting.py.

Edward

Terry Brown

unread,
May 27, 2013, 10:53:20 AM5/27/13
to leo-e...@googlegroups.com
On Mon, 27 May 2013 01:01:37 -0700 (PDT)
Fidel Pérez <fidel...@gmail.com> wrote:

> > data['b'].parent().remove(data['b'])

> And none of them will erase the button.

My bad, sorry, typing untested code into email. It's

data['b'].parent().removeAction(data['b'])

data['b'].parent() is a QToolBar, although removeAction() is a QWidget method.

Cheers -Terry

Terry Brown

unread,
May 27, 2013, 1:45:31 PM5/27/13
to leo-e...@googlegroups.com
On Mon, 27 May 2013 01:01:37 -0700 (PDT)
Fidel Pérez <fidel...@gmail.com> wrote:

> The first problem im encountering is that the command wont erase the
> button!! hehe... This is what I have tried so far:

Here's a working example just playing around - not sure exactly what
you're trying to do, but this creates a master button, which, when
clicked (and when first created) creates script-button buttons for all
its siblings. It refreshes these, deletes and replaces any that already
existed, when clicked.

Cheers -Terry

--- cut here ---
from leo.plugins.mod_scripting import scriptingController
sc = scriptingController(c)
data = {'clicks':0, 'sc': sc, 'our_buttons': []}
def my_cmd(c=c, v=p.v, data=data):
p = c.vnode2position(v)
g.es("Created from "+p.h)
data['clicks'] += 1
toolbar = data['b'].parent()

# get list of our buttons that are still on the toolbar, not removed by user
culls = [i for i in toolbar.actions() if i in data['our_buttons']]

for other in culls:
toolbar.removeAction(other)

data['our_buttons'] = []

existing = list(toolbar.actions())

current_pos = c.p.copy()

for nd in p.self_and_siblings():
if nd == p:
continue

c.selectPosition(nd)
data['sc'].addScriptButtonCommand()

c.selectPosition(current_pos)

# record list of buttons we added
data['our_buttons'] = [i for i in toolbar.actions() if i not in existing]

b = sc.createIconButton(
'Master',
command = my_cmd,
statusLine = 'Make buttons',
bg="light_blue"
)
data['b'] = b
my_cmd() # to create master button
--- cut here ---

Fidel Pérez

unread,
May 27, 2013, 1:53:49 PM5/27/13
to leo-e...@googlegroups.com
Wow really informative! Exactly what I needed, thank you!
To be honest I have been fighting 2 days trying to get buttons to erase others and my solution now was to make a list before creating them all, then store that list in all of them to delete them when pressed, but this is much better =)
Reply all
Reply to author
Forward
0 new messages