how to implement python feature's setEdit properly?

Need help, or want to share a macro? Post here!
DeepSOIC
Posts: 4507
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

how to implement python feature's setEdit properly?

Postby DeepSOIC » Tue Mar 14, 2017 9:53 pm

Hi!
I'm implementing a custom editing mode for ShapeGroup container in Part-o-magic. And I came across a problem.

I implemented setEdit(self, selfvp, mode), and it works. But, now if I right-click it in tree and choose "transform", transform is not initiated. Instead, my edit mode is launched.

So I added a check to mode, and if mode == 0, my editing is to be initiated, otherwise... what to do otherwise?
:arrow: Returning True switches the object into editing, but no dragger appears.
:arrow: Returning False or None suppresses the edit mode altogether.
The only working solution I found so far is to raise an exception in setEdit, for example raise NotImplementedError(). The only annoying thing about it is that the error is printed to report view.

relevant posts:
https://forum.freecadweb.org/viewtopic. ... it#p161062 - commit that changed the behavior.
DeepSOIC
Posts: 4507
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: how to implement python feature's setEdit properly?

Postby DeepSOIC » Tue Mar 14, 2017 10:01 pm

Code that I mentioned, with exception, that kind-of works:

Code: Select all

class ViewProviderShapeGroup:
    ...
    def setEdit(self, selfvp, mode):
        if mode == 0:
            try:
               #long boring irrelevant code that makes up my edit mode
            except Exception as err:
                App.Console.PrintError("Error in ShapeGroup setEdit: {err}\n".format(err= err.message))
                return False
            return True
        raise NotImplementedError()
User avatar
yorik
Site Admin
Posts: 8570
Joined: Tue Feb 17, 2009 9:16 pm
Location: São Paulo, Brazil
Contact:

Re: how to implement python feature's setEdit properly?

Postby yorik » Wed Mar 15, 2017 2:00 pm

I think what is not implemented is falling back from python to C++ edit modes.. For example, the C++ view provider of Parts has a mode for applying per-face color which is something like mode 4 or mode 5, i dont remember. If you make a c++ view provider derived from Part that implements mode 0, mode 4 is still called when needed. However, if you implement a python view provider, the C++ mode 4 is not called anymore, only python mode 4, if existing.

I looked at that some time ago then forgot about it... I'll have a look again
wmayer
Site Admin
Posts: 11241
Joined: Thu Feb 19, 2009 10:32 am

Re: how to implement python feature's setEdit properly?

Postby wmayer » Wed Mar 15, 2017 5:21 pm

Currently, the setEdit mode framework doesn't work very well when a sub-class wants to extend the modes of the base class. Have a look at this comment: https://freecadweb.org/tracker/view.php?id=1954#c7874

An alternative way would be to replace the int parameter with a string which gives a brief description (only for internal use) what it is about. Then for the programmer it's easier to decide which chosen mode to handle. Another advantage is that this way a sub-class could disable or remove an edit mode of the base class. In this case it would still have to know the above internal string to remove the corresponding action from the menu.

Any opinions?
DeepSOIC
Posts: 4507
Joined: Fri Aug 29, 2014 12:45 am
Location: Saint-Petersburg, Russia

Re: how to implement python feature's setEdit properly?

Postby DeepSOIC » Wed Mar 15, 2017 5:53 pm

I have no idea how context menu is involved here. But for calling c++ edit mode, I can suggest:
1. use NotImplementedError() as a command to call c++ setEdit.
Like it does now, just suppress its printout to report view
2. use special return value, like None.
This is somewhat equivalent to the exception approach, except a little bit less easy to read in code.
3. pass c++ setEdit as a python callable, in an additional argument to setEdit
Maximum flexibility, but it breaks all existing code because of changed function footprint.
4. expose c++ setEdit as a method of viewprovider (btw, does calling selfvp.setEdit(...) cause recursion?.. I didn't try, I assume it does...)

My preference is on 1+4 (implement both).
User avatar
yorik
Site Admin
Posts: 8570
Joined: Tue Feb 17, 2009 9:16 pm
Location: São Paulo, Brazil
Contact:

Re: how to implement python feature's setEdit properly?

Postby yorik » Fri Mar 17, 2017 5:02 pm

wmayer wrote:An alternative way would be to replace the int parameter with a string which gives a brief description (only for internal use) what it is about.


This would indeed make it easier, but not fundamentally change the base problem, no? If you create a subclass, being c++ or python, you would still need to know what are the edit modes implemented by the base class. But I think, anyway, if you make a sub class, you NEED to inform about what the base class does. And when you do, it doesn't matter much if implemented modes are 0, 1 and 5 or "edit geometry", "edit something else" and "change color", because you can discover that easily enough.

*EDIT* Actually not so easily... if the base class is itself a sub class of something else...

Maybe it should be just some code convention? Like, always add a comment or something in view provider code, that says what edit modes are implemented by this VP?

DeepSOIC wrote:4. expose c++ setEdit as a method of viewprovider (btw, does calling selfvp.setEdit(...) cause recursion?.. I didn't try, I assume it does...)


For me this should be automatic, like in Qt when you choose to handle an event or not... Ex: In your VP's setEdit method, you return True if you handled it, or False if you didn't. In that last case, the setEdit of the parent class is called. So you would only need to return False to call the corresponding edit mode of the parent class. This currently works for c++ VPs (I think) but not for python VPs.