Dynamic graphic user interfaces
What is the best solution for getting a tab graphic control in Max? I mean, something like the tabs in Google Chrome.
For example, take a patch that can be divided in 3 parts: "sequencer", "instrument", "effects". Each has a dedicated graphic user interface, and only one is displayed at a given time. For displaying the "sequencer" interface, you click on a tab or a button labelled "show sequencer" (same for "instrument" and "effects").
What is the clean way for doing this in Max?
----------begin_max5_patcher---------- 1860.3oc6b00jZaCE8Y1eEtj9V2Pjj+NYxLMSeoO0Icl7VRmc7GZA0XrYrEv tMS9uWKIaiEXiEaXAQVdAajrkt5ny8bkDR7saFMNL6AbwXi2Z7YiQi91MiFw ShkvnpuOZ77fGhRBJ3O13nr4ywozw2JxihefVmN1XEofP+k57RWNmjlfo7WD Vk38YozBx+g4oAl.17rYKo0ObcpKBnQyHoSuKGGQEVIzj8RFPGa9Eaw27l.L 9mpWhDyMnrv+809iaUqoAy4053OjSBRFyx362bC6iaUrsOGWTDLEuSa+ceIu 74LRBVlFM6tv7r0E3biYT5h29l2rd85IIjUjXRZAMeIC7JlThV0kRBIEGksL kWTlcAcntfNqdftZbVjD8wEXAtMdbC.0EpBqPU9EDvkcw1raT083hp8wn3lo Q3iFKvzR3L8wvLb9WRYe62UFPQJyEsdBbQj.0PUnlC6hoe2nl8wE0B41CNut TWEj2Tnl77pyIHeZkGdiYIgF6uYimGhiaCZcfCbWQW.GE774f.naPvbb6Roz 5EMvpVXI1PRvqv4EjrzV04nwpVWkn1znrjr7pNHd2SyGa8fIYQeUz1.0IFiu W8pJaANcySCppgMeH+jjzE43hRxZ.sp00tVCVlPuqasQ47uOHB26KuEsp9Ql lShyRYFgzaxRtt5pZs1ssZd9oAK53UoYYIgA4L89vDrTWUIsMHkLOfhoDg0f .MuGY9hbhvyrIMbZPYYLqHJOKIQpnD4rpibhwqHQ30jX5LdYsAqjBn0hZI4P Ik9dkijkj93G9ze7mFlsyqKgkcEW7ZLvd8z1k8BlXaYC78XjIaWjskO6NOfq mkImQ2zU0ie4F1nGWZB4t06zgm49jnFUKSItYCSgI41nwbylG6HpogNhZZsc DaAWNVhwTX40kW7QVIDcUI7pR3ktRH5LnDVq+Al3.gtN1u3TBgmiQ2grGVRC dbjz5qpN9JZ8WSWEzdYJnAOYBZajwZMHup69ITPKEutzT1YN9zYjhsj5d5qZ Dp2k931gV9CWNTJVLI28tjRPWy8LQ9pbJBVUW2u5uX0tT6zX76Xe7p+l8INM Vjh.cONv5BCZPXwONh9DWLIABJVnNSu8hlP2gQymb3DWK95XAcEBflPQmr4g EpPkR4Z7heFiWH4cI6g8a6ITApuPEf8Dpnc7kcb233z.QDpVBWwbXMQSrk85 1Inf0gGU31iONVfSLfFfCOr69vRy1HU2y0GZawCa5C6zMsydgvfzoLs55qC2 kXW0YvuX4rsR3N8IHsnO48ueOKw0Yhb6TERQU1s4KZ1sIBw4Z.+mS1MTLIJK fhraftvtQ5F6t5GPRbQA1M7kA69GmiJjMpCMNHEE4qKTTcazEhetceEInHuS GNtuI0+3qixxxiMtOK2nrYajcuwJBd8wkwBFVOF4vmEjEnW43NfbjXZTt8sQ G1AzOginSdmPHC5t.vyG4sO.1zb..t+ov1K9aZuA+q37N6A9s0ONOI84lu2A rIXp1JSaM0CZqb+2yrj6vjOwfqrUj7A0DA2vxozOsj1QyNOBsUKUCx+PDZq1 QYBr10ZHBKzQOv5EkAzHz53ZzYXi0AOdRc0g.6VHmu6fHmsVL7pnYkCeDeBG 1JanprAYc6AsRNNJtpAvW.g8ObATX0XUsTUA0+ZXn9WAKUQQDPOPwhnbxBpQ YHh3xByPrgHMZZfKxJHrHGF1SL9UnNB3BmeDzTrsb2CheBc+4HSun0y+ZaK9 D07a22qurDlTGCkk6KUwPwvvQNJ5FeUKbOq2opfHTO0BQWNZgU96dppE5ccj Pc.i9U6pUfZzV2q998tNxphgNZomO7hwy2CzZGWnfi+IbdkhFiRSd7vlKsXX Ml91pMFGyCYHNctct1t8yMJV9ciBEYKyip6Aq2AAFx1WLtfRRa1UKetYBpa8 byHwwxaiDNNShWjUNbP4sa1PcaGpYCgJZ1cz9Nq1splsoVY1r8zfATEVhu9Y 2pf2ro7pS1sop7DzkI8VuTSLU1t0LZBPQ2Re8yrUJlidA2rMVfRvsq9Y1p.2 N5kY6op1s+EoFXGsuyJbaqpS4tdAWD18EpY6pUlMz6PFP0EncCuPsaG8xrUM BudoABUMRIRuF+JBbgZ2JOtasxrsuHsZGEsZasxpcuHsZuKRFh+YPzt43n15 PWFeWYsfin2EPo4jvkTwhc19XCNMIKLHo5LE1rNwMGPtAOXc6joJGUudNMdC cZ+5aoreRGAWZPXW+cB7oVmTz7rkowhyBozeGV6d7Q4muTQ+5GYPISNVbGp4 NyMmRz1.Wmm.UTS0MqrnkNozNrCJMj+W+.z2A309tVmT5t2PViiRHQek8KhH UlRmOy1ERmaOga29HDOOKFOv+ZBaJdD.INcGspFgUsUC0FT1p3MTWnqikK+t xq.GYar8uwLRw+Vw3ur7p+K3La6oWwb5XYykzS6aLvtR5R65c2sm8NLYksJ4 IC0mUskseXVU4W99M+OfRaYKb -----------end_max5_patcher-----------
Or just look in the "more" subpatch of the [bpatcher] help file.
Thanks for your suggestions.
They work correctly, but I was talking about big interface panels (say 1024×768), and I can have many of them (up to about 10 maybe) so the bpatcher-based solutions are quite difficult to use in this case. Moreover some of my interfaces already contain a bpatcher and I have not tested bpatcher nesting in Max.
Alternatively, the bpatcher could embed different patches dynamically, but it would be problematic for implementing the patch-level preset system (classic pattrstorage + autopattr stuff), and I prefer to have all the patch in a single file so that everything is loaded when the patch is opened.
Currently I am using the following workaround:
1. The main patch is a horizontal narrow window, situated at the top of the screen.
2 Each interface is a big window that is displayed below the main patch window.
3. The main patch window contains buttons for loading the interface windows (loading one of them also closes the others).
4. All window open in presentation mode with "Fixed Initial Window Location" set to the proper value. The OS window decorations (bar, close button, menu, etc) are disabled (message "window notitle" to [thispatcher], and I use the patch with Max Runtime so that the Max low toolbar is not displayed either.
As the window decorations are taken in account when positioning the windows with "Fixed Initial Window Location", it’s a pain to implement but finally I made a patch template that works.
It’s certainly beautiful and useable, but for sure it will not display exactly the same way when using another computer because the window decorations will not have the same size :(
You can nest bpatchers. In my Gyre program, I have a bunch of note twisters at the top of the window that get swapped around by using a custom tab control. Basically, each twister is its own bpatcher. All the twisters then get included into a scroller bpatcher. The scroller bpatcher gets inserted at the top level. The scroller bpatcher takes messages from the top level about which pane should be shown, and scrolls to that position. Each of the twister bpatchers knows when it is selected, and enables output.
There are some examples in the collection of devices which come in MaxForLive.
I would place each UI into its own bpatcher, and place them on top of each other. Then show/hide them according to the tabs.
I found the bpatcher offset method always bad, as it forces you to a positioning logic which is most likely non intuitive and against the programming logic. Hiding has a simple clarity thanks to the presentation mode…
You could also try fullscreen mode, which should work the same in different OSes and screen sizes. You could even adapt the UI to the screen size.
But I would not like it as a user, I definitely prefer applications which do not take over my computer…;-)
Thanks for your answers.
I have a quick question about preset saving in Gyre.
Can you save the state of a graphic control directly in the Master preset system, even if this control is loaded into a bpatcher?
Or does it require to use a sub-preset system for each patch that you load into a bpatcher?
Same question actually.
In my current patch template, any control (of any subpatch/window) can either be saved:
* directly in the master preset
* in a "local" preset (and local preset numbers are saved in the master preset)
I would like to keep this functionality but cannot find a solution when using bpatchers (either tiled or nested, it’s not the problem in this case).
I do use bpatchers for loading abstractions that have a GUI, but in this case they always have a "local" preset system.
If I want the same GUI to be saved in the master preset system, I paste all the controls directly at the main patch level instead of loading the abstraction into a bpatcher.
I am using both these methods depending on the context (generally speaking, I would use local presets only for subsystems or modules that are likely to have the same presets in most tracks, say velocity curve module for example).
If the bpatcher has a scripting name, and has pattr or autopattr stuff in it, it will be visible to the pattr system at the upper level.
I have a mix of local and global preset saving. In reality, things get saved at the top level no matter what, even if there’s local storage, too. The local level has a library of local presets, but the current local state also gets stored at the top level when a preset is stored there. This does mean that the local storage always changes when the top level preset changes, but that’s more or less what I want. In my ideal world, just the address of the local storage would be stashed at the top level, but this is really only a storage efficiency concern.
Thanks everybody, I have finally found a solution using bpatchers and full screen mode.
The only problem I have is that I cannot show or hide a bpatcher.
All bpatchers have the same size and are placed at the same position in presentation mode. Depending on the selected view (using tabs) I would like to show the right bpatcher and hide the others.
Officially, sending "presentation 1" or "presentation 0" to the bpatcher’s leftmost inlet should work, but in practice this does not work, or I missed something. Same for the "hidden" message.
Both messages work correctly with other objects though.
I was working on OSX, will try it on Windows just now, maybe it works better.
So, how do you show or hide a bpatcher?
"script hide bpatcherScriptingName" or "script show bpatcherScriptingName" work with bpatcher
I just wonder why you can still send "presentation $1" to a bpatcher
Thanks for your example Chris. It is similar to the one shown in the bpatcher help patch, though yours is much cleaner.
Actually, the patches I am programming use large bpatchers (1070 x 780 in presentation). A single screen is too small for displaying many things, moreover I don’t like tiny graphic controls, especially on my 13′ laptop. This is why I use several views in parallel, that I launch with tab buttons. Most patches will have 5 to 10 views, perhaps more in some cases. You can really think of it as Google Chrome or Firefox, albeit with a static tab count for each patch. Also, I chose to stack the tabs vertically, at the left border of the window.
This is why the bpatcher offset technique is difficult to use for me (a 10700 pixel wide patcher would be quite impractical to edit). So finally I made a "main" patch that contains as many bpatchers as there are views. Each bpatcher loads a specific "view" patch. In presentation mode, the bpatchers are tiled but only one is shown at a time, using "script hide X" or "script show X" messages.
Of course the views can contain other bpatchers as nesting works indeed.
Thanks to your explanations I could finally make a preset system with:
> a main preset system that saves everything
> local presets, but they don’t interact with the main preset system
This is not a Max-based audio software, but a template for making a specific patch for each song.
Actually it is part of a slightly more complex architecture, with a host patch that can launch "track" (or "song") patches. I also made some "generic" abstractions (hence the local presets) that can be instantiated in track patches.
It displays identically on Windows and OSX. When I have a new desktop, the screen resolution will be different but I guess I can stretch the Max widgets automatically, using the built-in zoom.
There is only one problem I could not resolve:
All this system works in fullscreen mode. Suppose you have 2 patches opened in full screen mode. Patch 1 has a button for bringing Patch 2 to focus, and Patch 2 has a button for bringing Patch 1 to focus. It works, but on OSX you can see a horizontal stripe of desktop at the top of the screen, and this stripe has the same size as the OSX menu bar. When switching between both patches using the keyboard shortcut (Command-` on my computer), it works properly.
Not tested on Windows yet