View Full Version : Kryslin's Python Questions

07-31-2018, 07:51 AM
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.

07-31-2018, 11:36 AM
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.

07-31-2018, 11:38 AM
Whereas I am trying to write something for modeler....

07-31-2018, 11:49 AM
Hi again,

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

#! /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 = [
ctlMultiList1colwidth = [

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

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:

def ctlMultiList1CountFn(self,ctl,udat):

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):

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)

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

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

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:

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.mousebut ton_callback) # set the handler for mousebutton actions

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
return lwsdk.AFUNC_OK
# TODO: code your OK actions here
if self.retval==0: # TODO: code your custom cancel-button actions here
else: # TODO: code your custom ok-button actions here
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.


07-31-2018, 12:04 PM
Thank you.

07-31-2018, 01:11 PM
#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".

07-31-2018, 06:12 PM
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...

08-03-2018, 07:40 AM
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.

08-04-2018, 09:13 AM
...And a roadblock.

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)

08-04-2018, 01:32 PM
Is this all directly in process?

try the following:

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

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

08-04-2018, 03:24 PM
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.

08-05-2018, 08:18 AM
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.

08-05-2018, 11:56 AM
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.

08-11-2018, 02:46 PM
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

08-11-2018, 06:24 PM
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.

08-11-2018, 08:20 PM
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.

08-12-2018, 02:56 AM
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:

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...


08-12-2018, 07:09 AM
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.)

08-12-2018, 07:12 AM
its part of the regular sdk.. and pretty much exacly the same.

I filed it as a bug report, anyway...

08-12-2018, 11:22 AM
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!

08-26-2018, 07:37 PM
Another question, non-critical :

Is there a way, in the case of an error, to perform a specific task before aborting to console?

Her's why I'm asking... I was converting some of my fire and forget tools over to modeler, namely Weld Pairs and Stitch ( Weld Pairs Average). During debugging, I had a few instances of it erroring out of a mesh edit op. Should I try to run it again, It couldn't initialize another m esh edit op, and on the next try, it would crash, sometimes bringing up the crash reporter, sometimes going straight to the desk top.

Despite the PythonSDK's best efforts, I did manage to get both converted, and they both work nicely. But still, I have to ask if there is a way to close out the meshedit op before hitting the console with an error...

08-26-2018, 07:53 PM
you want to wrap your task inside try/except/raise/finally. that way. if the meshop errors.. its save. and you dont have to restart.

08-26-2018, 09:52 PM
Got it. I'll start doing that.

09-03-2018, 09:42 PM
Ok, the try:..except: ... finally: makes debugging thing much easier.

New question : I need to switch to point selection after I get done. I know this has to be a modeler command, called by mod_command.evaluate().

What's the character string I should be looking for? I've tried what I've used in lscript, "sel point", and variations thereof.

09-05-2018, 01:34 AM
You can look at this in the file "__init__.py" of the modeler functions of the "PRIS" module.
This file is located in
In this file you can search for "selpoint". What you find is how it will be handled in "PRIS". You will find many commands in this file, that you know already from LScript.

In the nuArchitect bundle I use the PRIS module which offers me most of the world of LScript.


09-05-2018, 06:58 AM
I'm aware of the PRIS module, yes. However, this isn't the selpoint/selpolygon lscript command, but switching between point mode, edge mode, and polygon mode, which was done via cmdSeq("Sel Point") / cmdSeq("Sel Polygon") in lscript.

I managed a kludge, which forced modeler into point mode; After I scan my polygons to check for curves (why doesn't lscript have fast_poly/point/edge scan?), I use mod_command.evaluate("SELPOINT CLEAR") before I iterate through the curves to get the start / end points. I uses meo.pntSelect(pID,1) to select my points while using meo.polSelect(ID,0) to deselect the polygons in that loop(meo = mesh edit operation).

09-22-2018, 09:16 AM
Ok, this is more of a "Is this possible" question.

I wish to wrap the F9 /F10 rendering options; mainly I want to check to see if FiberFX is applied to the scene, and if it is disabled, ask the user if they want to enable it. When the render finishes, i'd like the script to turn FiberFX off. While I know how to toggle an applied plugin on and off, is it possible to trap the closing of the render process (either by completion, or by abort)?

The reason : Frame by frame lag after the first render with FiberFX gets intolerable - I have examples of 20-30 seconds, just scrubbing the timeline - with the more layers you add. The work around is to disable the FiberFX pixel filter, and re-enable it before rendering. I'd like to automate that process, turning it on before rendering, and turning it off after a frame or sequence is done.

09-22-2018, 09:51 AM
yes.. possible... as master plugin. you can check for the events and do whichever you want on those events.

09-22-2018, 12:42 PM
Got it, thanks.

12-10-2018, 10:14 PM
Another question:

How does Lightwave evaluate open curves? I can properly select my span and the points needed to evaluate it, but my actual evaluation has a fair amount of error.

Keep in mind I've tried 3 different Catmull-Rom formulae - Vanilla C-R has the greatest amount of error, followed by a formula I pulled out of the include files. Closest I've gotten is centripedal C-R, but even that has a tiny bit of noticeable error. I'm probably missing something obvious, but I know other people have done it, so there must be a way to do it.

So, How?