2nd patcherview window flags

11OLSEN's icon

Hi, the [thispatcher] object is only useful to style the window of the "first view" of a patcher. So i'm trying to use an external to modify the window of a second view of the same patcher. Many things already work by accessing attrs and methods of the correct patcherview. But how do i change window flags like grow/nogrow , float/nofloat? That would save me a lot of fiddling with the native window on both platforms.

11OLSEN's icon

I found out window flags are set with a method of t_patcher: (https://cycling74.com/forums/objects-with-editing-windows)

t_atom rv; // return value
object_method_parse(patcher, gensym("window"), "flags float", &rv);
object_method_parse(patcher, gensym("window"), "flags nominimize", &rv);
object_method_parse(patcher, gensym("window"), "flags nogrow", &rv);
object_method_parse(patcher, gensym("window"), "exec", &rv);

but when I open a 2nd view:

void *result;
result = object_method(patcher, _sym_makeview);
patcherview_set_visible((t_object *)result, 1);

the new window does not take the flags into account. and there's no way to set flags for the new window.

What i need in the end is a "new view" that opens as floating window above a fullscreen window.
Atm the new view always opens in fullscreen if the app is in fullscreen mode.(macOSX)

Luigi Castelli's icon

Hi there,

so if you send the "window" message to the patcher it will only affect the current view.
To affect additional views you need to send the "window" message to the specific view you want to modify. The message arguments remain exactly the same.

A few lines of code are worth a thousand words...


t_object *patcher = NULL;
object_obex_lookup(x, _sym_pound_P, &patcher);

{
    t_atom av[2];
    t_object *secondview = (t_object *)object_method(patcher, gensym("makeview"));
    patcherview_set_visible(secondview, 1);
    
    atom_setsym(av, gensym("flags"));
    
    atom_setsym(av+1, gensym("nominimize"));
    object_method(secondview, gensym("window"), patcher, 2, av);
    
    atom_setsym(av, gensym("exec"));
    object_method(secondview, gensym("window"), patcher, 1, av);
}
    
{
    t_atom av[2];
    t_object *thirdview = (t_object *)object_method(patcher, gensym("makeview"));
    patcherview_set_visible(thirdview, 1);
    
    atom_setsym(av, gensym("flags"));

    atom_setsym(av+1, gensym("float"));
    object_method(thirdview, gensym("window"), patcher, 2, av);
    
    atom_setsym(av+1, gensym("nogrow"));
    object_method(thirdview, gensym("window"), patcher, 2, av);
    
    atom_setsym(av, gensym("exec"));
    object_method(thirdview, gensym("window"), patcher, 1, av);
}

If we think about the current view as the first view, the code above creates two additional views.
The second view will have the "minimize" flag disabled, whereas the third view will be a floating window with the "grow" flag disabled.

This should answer your question.

- Luigi

11OLSEN's icon

Thank you so much Luigi, perfect answer.

Roman Thilenius's icon


it is great that you are building something better than thispatcher,..

"Hi, the [thispatcher] object is only useful to style the window of the "first view" of a patcher."

...but why? i use thispatcher all the time to change between panel, palette, and regular view, move windows around or hide them, all of the commands work after initialisation too.
(?)

11OLSEN's icon

Hi Roman, I can explain the simple idea behind this. I have m4l devices which i want to be able to be displayed in a window floating above Live. And Max already has this concept of multiple windows displaying the same patcher.
Send "front" to a [thispatcher] in a m4l device. You'll see a perfect duplication of the device in a window. This is a second view of the same patcher but it doesn't float above Live. And all window related messages to thispatcher are applied to the first view which is the fixed frame that is diplayed in the Live UI.

But now, I can have completely different parameters for both views.

The window title says "sub patch" but this is actually the top level patcher of the m4l device..

11OLSEN's icon

Luigi, for the future, is there a way to find out the signature of object methods? How could I have known that the "window" method of the patcherview needs the additional patcher argument?

Luigi Castelli's icon

Yes, good question... in an ideal world the answer should have come from those with access to the source code: i.e. C74 people. That's why I didn't answer you immediately. I wanted to see if someone from C74 would answer. But it didn't happen. They don't seem to be too responsive to this kind of dev questions, and I didn't want your question to go unanswered because it is a very pertinent and legitimate one.

So the way to find out the signature of object methods (and other things) when you don't have access to the source code is to disassemble the Max executable.
Not the most enjoyable thing to do, but if you don't have access to the source code and those who do are not available to help, this kind of reverse engineering is the only way to find out information about the code... and sometimes even this is not enough.

11OLSEN's icon

OK, i understand. The forums is all we have and good guessing and try n' error skills.
Best,
O.

schlam's icon

..in your gif , you change the track selection in Live just after you floated the windows, ..hard to see what happens in the original track. Is the device still 'docked' and reflects the changes of the floating one ? and vice et versa ?
Are both the same 'visualization" of the same patch ?

11OLSEN's icon

ya, i'm changing track to show the window is floating. Yes, just 2 views of the same patch. If you turn a dial in new view you'll see it moving in the "docked view".

schlam's icon

wonderful
..can't wait to see that!

11OLSEN's icon

Luigi, I'm really close to having the external finished for both platforms. One last thing I would like to add is highlighting an object in a view for Max educational tasks. I think, hence the name, it's the "tinge" and "fadetinge" methods. But the only thing i found out with "tinge" is that it seems to expect an int as first arg and a pointer as second. but any expected combination doesn't work:
//object_method(x->w_patcherview, _sym_tinge, 1, &rect);
//object_method(x->w_patcherview, _sym_tinge, 1, obj_box );
//object_method(x->w_patcherview, _sym_tinge, 1, box_id_sym);
//object_method(x->w_patcherview, _sym_tinge, 1, patcher, obj_box );
//object_method(x->w_patcherview, _sym_tinge, 1, patcher, box_id_sym);
and i tryed many more.
You know the signature?
Is this the method that shows this yellow transparent panel above an object's box?


Luigi Castelli's icon

Hi there,
congrats for your external. It seems really cool.
Yes, the tinge method is something that would be super-handy to have as part of the Max API as well.
Unfortunately it is not so...

Here is the signature that I found, which I am pretty sure is correct.
However I am not sure what each argument is supposed to represent.

void patcherview_tinge(t_object *pv, long count, t_atom *objects, t_atom *retv, long flag1, long flag2, long flag3)
{
object_method(pv, _sym_tinge, count, objects, retv, flag1, flag2, flag3);
}

So let me tell you what I am guessing the arguments are:
pv: pointer to the patcherview (no brainer)
count: the number of objects in the objects array
objects: an array of atoms of A_OBJ pointers representing the objects in the patcher/patcherview.
retv: no freakin' idea... I interpreted it as some kind of return value, but I am probably wrong.
flag1, flag2, flag3: these are 3 flags which are supposed to affect the resulting tinge operation.
They can be zero or non-zero (off/on), They probably set some kind of options, but I am afraid that's all I could figure out.

You may have to mess with it a little bit to see if you can get something useful out of it.
If you do, please post back your findings.
I would be curious to know too since I have been wanting to use this method as well, but I was never able to.

Good luck!

- Luigi

👽'tW∆s ∆lienz👽's icon

the tinge method is something that would be super-handy to have as part of the Max API

+1 to this from me too

11OLSEN's icon

thanks Luigi (object_method(pv, _sym_tinge, count, objects, retv, flag1, flag2, flag3))
The count acts very strangly. If i use a single atom like this it works:
t_atom a;
t_atom rv;
t_object *obj = (t_object *)object_method(x->jp, _sym_getnamedbox, gensym("me"));
atom_setobj(&a, obj);
object_method(x->w_patcherview, _sym_tinge, 1, &a, &rv, 0, 0, 0 );

the tinge becomes visible and fades out after a sec.

Creating an atom array with 2 object, I have to set the count to 3 or only the first object is tinged.
Using 3 objects I have to set the count to 7.
Using 4 objects I have to set the count to 13 !
Without understanding this I can't calc the count for a number of objects.

retv returns A_NOTHING or undefined type numbers.

For flag 1 and 2 I couldn't notice any change in any combination. Flag 3 set to 1 keeps the tinge alive and doesn't fade it to transparent. The big question is how to clear this static tinge for an object. Called multiple times, it's layering tinges on top until there's no transparency left. Maybe "fadetinge" can clear them?

BTW: I'm using "showtarget" which is already better than nothing. It places an outlined red dot marker somewhere in the view.
//on
object_method(x->w_patcherview, _sym_showtarget, 1, int X, int Y);
//off
object_method(x->w_patcherview, _sym_showtarget, 0);

Luigi, maybe you can also confirm this signature. thanks




Luigi Castelli's icon

Hi Olsen,

as far as the signature for patcherview_showtarget() goes, what you have is correct.
Here is the signature:
patcherview_showtarget(t_object *pv, long state, int x, int y);

As far as the tinge method goes, I am afraid that's as far as we'll get without C74's help.
You already got it somewhat working, which is something I was never able to do.
It seems to make it work properly you need a combination of tinge and fadetinge, but it is hard to know how it is supposed to be used.

BTW, I double checked and I noticed that the rv argument is not a return value but an input value to the function.
That's why you weren't seeing anything meaningful being returned in there.
I believe it somehow affects the type of tinge action, so you need to define the atom in your code and pass it.
Maybe that in combination to the objects arg will give new meaning to the count arg???
Sorry, I know it's a long shot but I am not able to be more precise.

As I said, please take everything I say with a grain of salt as lots of it is just guesswork.
As you have seen, the arguments I guessed for patcherview_tinge() may not even be the correct ones in the end.
It seems the count arg is somehow related to the number of objects to tinge but it is not the real object count.

Again, if C74 could spare 5 minutes to point us in the right direction, that would be highly appreciated. Maybe we could start a new dev thread on how to tinge objects in a patcherview tied to a feature request to include the tinge method in a future version of the SDK?

- Luigi

11OLSEN's icon

I can add that if flag 3 is set, the "tinge" method is returning a reference to the tinge which can be cleared later with "fadetinge".
void *result = NULL;
result = object_method(x->w_patcherview, _sym_tinge, 1, &a, &a2, 0, 0, 1);
object_method(x->w_patcherview, _sym_fadetinge, result);

But the 2 pointers are still confusing. It's interesting that you can exchange them (first empty, second holds objects) and it behaves exactly the same. Objects are tinged but the count is off.

Luigi Castelli's icon

the signature that I get from fadetinge is:patcherview_fadetinge(patcherview *pv, void *result, long n);

So I bet that the extra long argument allows you to set the fade time.

Ok, we can't give up now then... we almost have it.
Email me off-list at: superbigio[at]yahoo[dot]com

schlam's icon

Hello 11olsen.

happy new year !
...one year after I am still veryyyy entousiast with this external..

Did you managed to make it working ? maybe a beta version is publishabled ?

thank you!

Julien

11OLSEN's icon

Hi Julien, happy new year. Wow how fast this year went over. I only have a Windows prototype. Other stuff prevented me from porting this to Mac. And a motivation killer is a bug with jit.pwindow which doesn't display properly in the second view of the device. I reported this as a bug to c74 and they promised to look into it but never got back at me.

schlam's icon

Hello 11olsen.

happy new year ! ...one year after I am still veryyyy entousiast with this external..

Did you managed to make it working ? maybe a beta version is publishabled ?

thank you!

Julien

EDIT : I am only on windows in case of Mac specific problem...

=))

11OLSEN's icon

Hi, yes, I have a beta version working on both platforms. Contact me so I can send via email!
best,
O.

schlam's icon

done.

thank you !!

11OLSEN's icon

@SCHLAM Do you have an example so I can reproduce the bug. I have not noticed something like frozen UI.

schlam's icon

Hello !

To reproduce the issue :

In the little bpatcher with 2 live.dial and two sliders, add an observer of any live parameter.

Then if you open this bpatcher with your (wonderful=) external,
the bpatcher in floating window only reports the value if the track containing the device is selected.

Also while the track containing the device is not selected, if you move the dial controlling this parameter,
the corresponding value will move in Live but not in the floating window...
...until you select the track where the device is AND select the floating window..
EDIT: selecting the floating window (while another track is selected) doesn't refresh it until you select the track where 11.newview is..

Here is a picture of the bpatcher I tried, it only get/set the master volume.
can you reproduce ?

here window10 / Live 10.2.10b2 / max 8.5.2


11OLSEN's icon

Please copy compressed?

schlam's icon

Also,
I didn"t manage too to move left or right the position of the scrollbar in the docked device.
It's surely because I didn't understand well how to set the rectangle I want to be shown in the floating window..

I love too your trick with the 2 live.dials bigger but :
It should be great to do not have to click on a "colored pixel" of the dial to be able to move it.
It should be great too to choose if you want these big dials to be displayed or not when the Live app is focused or not

11OLSEN's icon

There are ways to prevent the click-through background but let me check the mapping thing first.

schlam's icon

Please provide at least 10 characters

Max Patch
Copy patch and select New From Clipboard in Max.

11OLSEN's icon

I can reproduce, it seems to be a special case with bpatcher. Thanks for spotting this! When the last view of a patcher containing the bpatcher is closed, the GUI in an additional opened view of the bpatcher isn't updated anymore.
Hope add a fix/workaround to the external soon.
to move the visible patcher area of a view you have to use the visiblecanvasrect messages after the view is visible. If you mean scrolling the docked view you'll have to use the abstraction in the test device that makes this possible, otherwise Live resets the canvasrect everytime.

schlam's icon

I am sure you will find a fix. =)

I noticed too that [panel] 's property "drag window" is greyed in the inspector

schlam's icon

...just a question..

if for example you click several times on the first button of your test device, several floating views will be created, then it's only on the last created one that the red close button is working. For the others one, how do you close them if they have been opened with a "window flags notitle" argument, and the "windows10" close button is not available ?

11OLSEN's icon

Best is to make sure the user is not allowed to open multiple additional views. eg check the "isopen" output. The external can only be attached to one view at a time. But it is also possible to attach the object to already opened views and even other patchers. see "open_specials" subpatcher. You can use multiple instances of the external if you really need to handle 3 or 4 views of the same patcher at the same time (rare case, i think).

"notitle" windows are closed with a "close" msg to the object (provided that it is attached to the contained view)

schlam's icon

thank you again!
let me explain what I am trying to achieve.
Maybe you can tell me some tricks...
I scratch my head so much..

I need 3 max patchers in my setup:

-Patcher1 is a maxpatch that is not linked with Live (I need it to exchange stuffs with Patcher2 in Live) it runs on standalone max8.5.2. it doesn't have to be concerned by 11newview ...
-Patcher2 is an audio device in Live 11.2.10b2
-Patcher3 is in Patcher2 (but maybe you will advice me to put it elsewhere..)

When the Live set is opened :
-Patcher3 auto opens. It is a very little patcher with transparent bgcolor and two toggles (and a draggable panel) that sends "11newview" message to control Patcher2's view (the main device) . Patcher3 appears at the top of Live like 2 stock toggles in an empty space of the Live's toolbar.

-----toggle1 : open/close Patcher2 in floating view (and always patcher2 even if another patcher or window is focused..) .Patcher2 is opened by Patcher3 with some characteristics ; "Preset_A".... (zoomfactor X, size Y Z...etc...). or Preset_B etc..

this "open/close" toggle, recalls the last position of Patcher2 if it has been move, and recalls the characteristics of the last "Preset_X" chosen.

-----toggle2 : change the characteristics of Patcher2'view presets( _A, _B, _C)((zoomfactor, size...etc...) on the fly. (toggle1 always open/close patcher 2 whatever the preset and remember it.

I use since a longtime a working version of this mechanism but i don't manage to implement that with 11newview.. Each time I think I am close : little Patcher3 becomes the patcher controlled by 11newview. I don't manage that "Patcher2" allways stays the only patcher controlled by 11newview whatever I focus another window. There is only one 11newview in Patcher2. In patcher3 there is just toggles..

I tried some stuff in your special patcher but really don't understand well how to achieve that...

Sorry for my bad english.

I cannot copy a patch for now, but maybe you have an example of this kind of routine ?

cheers !

Thanks again for your amazing work






11OLSEN's icon

Too bad that you can't send me something as it is time consuming to build it from your description. If there's sensitive code just take it out.? But it sounds like an easy task. Simply use a separate 11newview for patcher 2 and 3 like you would do with [thispatcher].

schlam's icon

I will try to send you something today..
The main thing I don't understand is how to allways "bind" 11newview to a dedicated patcher whatever happens. I thought that banging "open Patcher2.maxpatch, open invisible etc....." will allways open Patcher2 when "Patcher2.maxpatch" is one of the outputs of the message "toppatcherlist".
But while patcher3 is opened once, the toggle open/close on it banging to "open Patcher2.maxpatch, open invisible etc.....", close/open itself and not Patcher2 anymore...

well...hard to talk without my computer..
thanks for your help !

11OLSEN's icon

changing the patcher focus is only for special cases. don't mess with it if you don't need to. The default patcher focus of the object is on the patcher containing it, put a newview object into each of the patchers. You really have to think of it as a [thispatcher] with some extra features, The second thing is the view focus/binding which is normally on the new created view. any view that was in focus before is released but not closed.
But we could save many words if you send something to work with. Also I think the conversation is maybe not so interessting for forum members and we know each others email adr. ;)