Kryslin's Python Questions

Kryslin

Active member
Since I have one of these for lScript, and I'm diving into python...

1) First question! Is it just me, or is there no file in the python docs for lwsdk.LWPanels? For me, it appears to be absent,
(If it's not me, I'll bug report this one.)

2) This one goes to Oliver... I've used the OD Tools AutoGui tool to create a list box panel. Should this work "Out of the box"? As in, I run it from the Python menu button, it creates a do-nothing menu. If it should, then something's not right on my end. I've tried the example from Kanuso's thread, and it does nothing as well. Zip, nada, nothing. I think I tracked down where I was getting the indent errors - It's notepad++. I have to use it's Tabs -> Spaces before loading into lightwave's console. Still nothing when entered, though.
 

KANUSO

New member
Hello Kryslin,

finding Information on how to work with Panels and controls was hard to me too. The only source I found was this Forum here and the help command from python itself. You can use the help command to generate a text file, that can be used as Inspiration to how the things must go. As I told in the LScript Forum, I'am about to transfere the nuArchitect bundle to Python. There you can find than some info on how to do some things. Even a GUI-Designer will be added to nuArchitect. With this designer you can create GUI's in a graphical way (WYSIWYG). It can create GUI's for Modeler and for Layout. Because there are some differences, this brings me to an idea of why the scripts don't do anything. Maybe you run it from the wrong Environment. The script that was postet in my thread is a generic and should run in layout.

I hope this helps you out.
KANUSO
 

KANUSO

New member
Hi again,

the class line should read somthing like...
class myScript(lwsdk.ICommandSequence):
and it Needs:
def process(self, mod_command):

Code:
#! /usr/bin/env python
# -*- Mode: Python -*-
# -*- coding: ascii -*-

"""
Example1: This code is generated by nuSoft's GUI-Designer
"""

import lwsdk

# TODO: Edit the following block to your needs
__author__         = 'Name'
__date__           = 'Date'
__copyright__      = 'Copyright by...'
__version__        = 'Version'
__maintainer__     = 'Maintainer'
__email__          = '[email protected]'
__status__         = 'under developement'
__lwver__          = '11'

# space for global variables

class Example1(lwsdk.ICommandSequence):
    def __init__(self,context):
        super(Example1, self).__init__()

    retval = 2   # the mousebuttonhandler will close the dialog if there is 0 (cancel) or 1 (ok)

    # TODO: use this variables as the control variables and initialize them with your needs


    ctlMultiList1txts = [
        ['Red', '255', '0', '0'],
        ['Green', '0', '255', '0'],
        ['Blue', '0', '0', '255']    
    ]
    ctlMultiList1titles = [
        "Color",
        "R",
        "G",
        "B"    
    ]
    ctlMultiList1colwidth = [
        100,
        45,
        45,
        45    
    ]

    def isinbox(self,x,y,x1,y1,x2,y2):
        if x>=x1 and x<=x2 and y>=y1 and y<=y2:
            return(1)
        return(0)

    def isinctl(self,x,y,ctl):
        return(self.isinbox(x,y,ctl.hotx(),ctl.hoty(),ctl.hotx()+ctl.hotw(),ctl.hoty()+ctl.hoth()))

    # control functions of ctlMultiList1 --------------------------------
    def ctlMultiList1NameFn(self,ctl,udat,row,col):
        if row<0:
            return(self.ctlMultiList1titles[col])
        return(self.ctlMultiList1txts[row][col])

    def ctlMultiList1CountFn(self,ctl,udat):
        return(len(self.ctlMultiList1txts))

    def ctlMultiList1ColumnFn(self,ctl,udat,col):
        if col==0: return(100)
        if col==1: return(45)
        if col==2: return(45)
        if col==3: return(45)
        return(0)                 # no more columns

    # control functions of ctlButton2 --------------------------------
    def ctlButton2EventFn(self,ctl,udat):
        self.retval=1
        self.panel.close()

    def createControls(self):
        self.ctlMultiList1 = self.panel.multilist_ctl("", 260, 1, self.ctlMultiList1NameFn, self.ctlMultiList1CountFn, self.ctlMultiList1ColumnFn)
        self.ctlMultiList1.move(20,10); self.ctlMultiList1.set_w(260); self.ctlMultiList1.set_h(150)

        self.ctlButton2 = self.panel.button_ctl("OK")
        self.ctlButton2.move(10,175); self.ctlButton2.set_w(80); self.ctlButton2.set_h(22)
        self.ctlButton2.set_event(self.ctlButton2EventFn)

    def panel_resize(self,ctl,udat,width,height):
        # TODO: implement code for panel resize handling here
        return

    def mousemove_callback(self,panel,udat,btnflg,x,y):
        # TODO: implement code for mouse move handling here
        # Info: all mousemove handlers of the controls will be called here
        # Info: the actions can be done here, or in the called handler
        return

    def mousebutton_callback(self,panel,udat,btnflg,x,y):
        # TODO: implement code for mouse button handling here
        # Info: all mousebutton handlers of the controls will be called here
        # Info: the actions can be done here, or in the called handler
        if self.retval == 0 or self.retval == 1:
            self.panel.close()


    def process(self, mod_command):
        reqw = 300      # define the width of the requester
        reqh = 210      # define the height of the requester
        self.ui = lwsdk.LWPanels()
        self.panel = self.ui.create('Example1')  # create the panel
        self.panel.set_resize_callback(self.panel_resize)  # define the handler for resize events
        self.panel.set_mouse_move_callback(self.mousemove_callback)     # set the handler for mousemove actions
        self.panel.set_mouse_button_callback(self.mousebutton_callback) # set the handler for mousebutton actions
        self.createControls()



        self.panel.setw(reqw)
        self.panel.seth(reqh)
        if self.panel.open(lwsdk.PANF_BLOCKING | lwsdk.PANF_NOBUTT | lwsdk.PANF_MOUSETRAP | lwsdk.PANF_MOUSETRACK | lwsdk.PANF_FRAME) == 0:
            # TODO: code your CANCEL actions here
            self.ui.destroy(self.panel)
            return lwsdk.AFUNC_OK
        # TODO: code your OK actions here
        if self.retval==0:            # TODO: code your custom cancel-button actions here
            pass
        else:            # TODO: code your custom ok-button actions here
            pass
        self.ui.destroy(self.panel)
        return lwsdk.AFUNC_OK


ServerTagInfo = [
                    ( "PyExample1", lwsdk.SRVTAG_USERNAME | lwsdk.LANGID_USENGLISH ),
                    ( "Example1", lwsdk.SRVTAG_BUTTONNAME | lwsdk.LANGID_USENGLISH ),
                    ( "Utilities/Python", lwsdk.SRVTAG_MENU | lwsdk.LANGID_USENGLISH )
                    ]

ServerRecord = { lwsdk.CommandSequenceFactory("PythExample1", Example1) : ServerTagInfo }

This code is generated by nuGUIDesign (no changes are made)
This example should run in Modeler

The Info-Comments in the mousemove are telling that all handlers will be called there. This script doesn't have handlers active. The script is only to demostrate how it should go in the Modeler.


Regards,
KANUSO
 
Last edited:

oliverhotz

New member
#2, yeah.. it should work out of the box... as i mentioned, feel free to join the discord... I simply dislike forums and the "time it takes between interactions"... its soo much easier "live".
 

Kryslin

Active member
I had to resort to some BASIC debugging tricks, but I managed to get the Auto GUI version to work.

Because I'm working under modeler, I had to change the class type to ICommandSequence, the process line to self, mod_command , and the server record to CommandSequenceFactory.

Then, i discovered that the multilist control didn't have enough handlers , so I added a null function (Takes arguments, does nothing, returns).
Then, one of the provided callbacks(*_name_2d) didn't take enough arguments (I added a dummy argument to the function def).

Then, it worked, under modeler.

Now, to get the selected values from the control...
 

Kryslin

Active member
More progress... I'm managing to read my selection out of the list box. Python is indeed a different beast. Whereas I could grab the selected indices in lScript with a get value call, I have to maintain an array of flags for selected items.

Next step, is to load style map names. That, I've got done already. Then, to process them.
 

Kryslin

Active member
...And a roadblock.
Code:
def process(self, mod_command):
...
	self.cmop = mod_command;
...
	self.meop = self.cmop.editBegin(0, 0, lwsdk.OPSEL_USER)
	if not self.meop:
		print ("Failed to init Mesh Edit Operations...")
		return lwsdk.AFUNC_OK  #<-- Always winding up here, self.meop fails to initialize...
...
	self.meop.done(meop.state, lwsdk.EDERR_NONE, 0)
	return lwsdk.AFUNC_OK

For some reason, the call to editBegin fails. Fortunately, I exit gratefully, noting what has happened.
The result is the same, whether or not I use mod_command or the self.cmop variable. I simply don't know enough about what
is going on here to determine what is wrong and how to fix it...

So, any ideas? Yes, I am running this script under modeler, with geometry present (LW2018.0.5, LW2018.0.6)
 

KANUSO

New member
Is this all directly in process?

try the following:

Code:
    def process(self, mod_command):
        mo_co=mod_command
        meo=mo_co.editBegin(0, 0, lwsdk.OPSEL_USER)
        print meo
        if not meo:
            print "no"
        else:
            print "yes"
            meo.done(meo.state, lwsdk.EDERR_NONE, 0)

If this doesn't work, than there is something wrong.
 

Kryslin

Active member
To answer your question : Yes, it is. The ellipsis ("...") indicate where blocks of code were omitted.

I'll give your example a try and get back to you. I'm currently rendering, so it might be a while.
 

Kryslin

Active member
Your example did work. Now to find out why mine, which is essentially the same, doesn't...

*edit* I found the error... I don't know what a semi-colon does in Python, but it messes things up...

I had this in my code:
cmop = mod_command;

The semi colon was killing whatever was in mod_command, causing an issue.

Delete Style Maps (for modeler) now works, in Python.
 
Last edited:

KANUSO

New member
you can use the semicolon to separate commands in 1 single line.

for example:
control.set_w(100); control.set_h(22)
the last command should not have any semicolon.
 

Diepgroen

New member
Oliver is right, are you guys on Discord? Discussing Python there is easier and you get interaction much faster. All LightWave stuff... Come join! There is also robust python code styling in Discord. https://discord.gg/cfTKQw OD has a sdk-python-lscript channel
 

Kryslin

Active member
I am seriously thinking about it. Part of the problem is that the Python SDK documentation is incomplete - nothing on panels, or controls on panels. I had to trouble shoot a missing argument in an auto generated GUI. Not an easy task, with incomplete documentation.

And yes, I know about the help command... pcore never lets me enter the interactive mode.

I'll be gearing up to start in on my hair tools in Python next week.
 

oliverhotz

New member
I am seriously thinking about it. Part of the problem is that the Python SDK documentation is incomplete - nothing on panels, or controls on panels. I had to trouble shoot a missing argument in an auto generated GUI. Not an easy task, with incomplete documentation.

And yes, I know about the help command... pcore never lets me enter the interactive mode.

I'll be gearing up to start in on my hair tools in Python next week.

its part of the regular sdk.. and pretty much exacly the same.
 

KANUSO

New member
Hello Kryslin,

the problem with the docs in python had hit me too. So I digged myself deeper into the lwsdk and as a result I wrote a python script that mainly is to create python scripts. You can create a GUI in a WYSIWYG art and let the script do the work for you. You can save the raw-definitions, so it is no problem to change the design. Because a Picture says more than 1000 words here a screenshoot:
nuGUIDesign.jpg

As you can see, there are GFX-Buttons as well as Tab in Tab in this demo.

This GUI-Designer gets part of the nuArchitect bundle which will be complete in python. I'm on the way to create the helpsystem for the python Versions. This may take some days, but it is on the way to get released.

The idea of discord is fine, but the Information should go in this Forum too. The main reason is: This is the official place of the lightwave Forum. How should the developers know our thinking, if we don't write it here?

I will look for discort in the next days...

Regards,
KANUSO
 
Last edited:

Kryslin

Active member
Most of mine are fire and forget modeler scripts, like my hair & spline tools ( and stitch, fuse poly pairs, and my little volume cutter), so a UI isn't an issue. Even my fractal foil generator has a simple UI.

However, Things like Style Comb... that's probably the most complicated UI programming wise in lscript I've done. And, I've got ideas... ( Be afraid... be very, very afraid.)
 

Diepgroen

New member
Kanuso, thats a sexy UI creator :) I understand your point. You can always be active here. The speed of interaction is different there. LW Developers on Discord are really helpful when you are stuck. You can interact directly or in private if information is delicate. We love to see more developers working on LightWave plugins and script. Good job!
 
Top Bottom