# Liine Lemur (for Android) - creating objects on-the-fly



## quickbrownf0x (Jan 31, 2019)

I'm wondering if it's possible to dynamically create and render an object, like a Monitor or Container by triggering a (global) function/bit of script. Like so;

decl contain_obj = new Container();// create the object
setattribute(contain_obj, 'rect', {0,0,640,480}); // set its dimensions and placement
show(contain_obj, 1); // render on screen.

Or maybe create a function;

function createContainer(id, positions, dimensions)
{
decl contain_obj = new Container(id);
setattribute(contain_obj, 'rect', {positions[0], positions[1], dimensions[0], dimensions[1]});

show(contain_obj, 1);
}

And then whenever I need it I can just go;

createContainer('oohlookatthisshinynewcontainer', {0,0}, {1280, 960});

...tie that sucker to a button, you know - something like that....

Liine's own documentation's a bit shit. Can't find anything about it. Does anyone know, or has anyone tried this? Or am I just being too much of nerd and do I have to accept the fact that my fancy Lemur UI won't be as flexible and dynamic as I would like it to be? Because (as far as I know) the alternative is to hard-code a ton of stuff, including things like patch articulations and their labels. Which would suck. I mean, that's just stupid.

Cheers,
Dj.


----------



## WindcryMusic (Jan 31, 2019)

I don’t think it is possible to dynamically create objects in Lemur (sure would be nice if one could). But you don’t have to hardcode things like the text on labels ... that at least can be set via the object attributes. I do so all over the place in my template, along with hiding and showing buttons as needed.

If you really need more control, I suppose you could use the Canvas object to dynamically draw your own buttons as needed. I’m not sure if you can get them quite as pretty as the built-in button objects, but it does give you some flexibility. I use the Canvas object in my own template to create and dynamically color and label a keyboard graphic, as seen here:


----------



## pmcrockett (Feb 1, 2019)

One other thing that can help get around the fact that you can't dynamically create objects is that you can, to some degree, dynamically address objects from within the code. The functions findobject(), getfirst(), getnext(), getobject(), and getparent() allow you to navigate the objects' tree structure without necessarily knowing the objects' specific names. See pgs. 128-129 of the manual for the (limited) documentation on these functions.

You can, for example, have code that will iterate through all objects in a folder whose names fit a certain pattern. Below is some code grabbed from one of my projects that iterates through 99 articulation buttons named ArtCell01 through ArtCell99, each of which is an identical object. I still needed the 99 objects to already exist, but I just had to copy/paste them in the editor. The pasted duplicates were auto-named correctly, and the code automatically found them.


```
decl curCell = Editor.ArtCellCon.ArtCell01;
while (getattribute(curCell, 'name') <= 'ArtCell99')
{
    //code that operates on the button goes here
    curCell = getnext(curCell);
}
```

As Windcry mentioned, you can label, position, and hide the buttons from within the code, so you can use this iteration to set up the buttons however you want and hide the ones you're not currently using.

If you want to do something like this but need better text parsing abilities for the name comparisons, I posted a string to vector text parser in some thread a while back that I can dig up for you.


----------



## WindcryMusic (Feb 1, 2019)

pmcrockett said:


> One other thing that can help get around the fact that you can't dynamically create objects is that you can, to some degree, dynamically address objects from within the code. The functions findobject(), getfirst(), getnext(), getobject(), and getparent() allow you to navigate the objects' tree structure without necessarily knowing the objects' specific names. See pgs. 128-129 of the manual for the (limited) documentation on these functions.



Yep, this is good to do too if you don't already (my Lemur template is *highly* dependent on such things).

One thing that tripped me up for a while was not understanding that there are different API methods for getting the values of expressions as opposed to screen objects. (I do much of both.) Look at getexpression(), as opposed to findobject() and getattribute(). And don't overlook the findchild() call that was added in the most recent update, as it is a handy shortcut.



pmcrockett said:


> If you want to do something like this but need better text parsing abilities for the name comparisons, I posted a string to vector text parser in some thread a while back that I can dig up for you.



As an aside, I did try using that text parser code of yours (which is a pretty impressive hack) at one point. For a few simple parses it works perfectly, but when I gave it some real work to do it crashed Lemur badly after the first several times it ran ... I think it ran Lemur out of stack space or something like that. So I'd have to recommend some caution on that one.


----------



## quickbrownf0x (Feb 1, 2019)

Cool, thanks guys. That makes sense. @WindcryMusic/David that auto key mapping thing looks pretty nifty. Same goes for this; 



Really cool. Care to share that project file? lol


----------



## pmcrockett (Feb 1, 2019)

WindcryMusic said:


> As an aside, I did try using that text parser code of yours (which is a pretty impressive hack) at one point. For a few simple parses it works perfectly, but when I gave it some real work to do it crashed Lemur badly after the first several times it ran ... I think it ran Lemur out of stack space or something like that. So I'd have to recommend some caution on that one.


Good catch. I didn't thoroughly stress test the parser at the time, but I just dipped into the project again and it looks like Lemur cuts loops short and/or doesn't run them at all if they're too long, so my guess is that either the parser is encountering strings it can't match and Lemur is freaking out because the function's built-in failsafe loop limit is too high or that generally running the function embedded too deep in other code might be hitting the loop limit. If I can duplicate/fix things, I'll bump the other thread with an update; thanks for bringing this to my attention.


----------



## WindcryMusic (Feb 1, 2019)

quickbrownf0x said:


> Cool, thanks guys. That makes sense. @WindcryMusic/David that auto key mapping thing looks pretty nifty. Same goes for this;
> 
> 
> 
> Really cool. Care to share that project file? lol




Hehe. The specific project probably wouldn’t help you, as it is pretty specific to my configuration including use of ArtZID v2, but I have had the thought to make a YouTube video or two to show and discuss some of the programming behind it. Maybe that would interest you?

By the way, that touch-driven UI shown in my 2nd IG post is still in there, but I hardly ever have to select anything manually anymore like that, because I now use Osculator along with some additional Lemur programming to have articulation pages selected automatically when I change Logic tracks. (Implementation hint: I have a container full of expressions like “t1”, “t2”, etc., each containing a vector with one of the track names in my Logic template, along with info on which articulation tab and page to bring up, and then I use some of that container iteration coding mentioned earlier in this thread to walk through until I find a match for the newly selected track in Logic. Works a treat, if I may say so myself.)


----------



## Garlu (Feb 2, 2019)

WindcryMusic said:


> ... I have had the thought to make a YouTube video or two to show and discuss some of the programming behind it. Maybe that would interest you?



PLEASEEEE!!!! 

That would be amazing and much appreciated it!


----------



## quickbrownf0x (Feb 3, 2019)

WindcryMusic said:


> Hehe. The specific project probably wouldn’t help you, as it is pretty specific to my configuration including use of ArtZID v2, but I have had the thought to make a YouTube video or two to show and discuss some of the programming behind it. Maybe that would interest you?



I'd totally understand if you're too busy, but yeah - that would be awesome. Odd how little information's out there on this topic. Not what I expected. A few support pages and a handful of dudes on Youtube - that's pretty much it.



WindcryMusic said:


> ...I now use Osculator along with some additional Lemur programming to have articulation pages selected automatically when I change Logic tracks. (Implementation hint...)



Sweet, I'll check that out. Thanks everybody.


----------



## WindcryMusic (Feb 3, 2019)

quickbrownf0x said:


> I'd totally understand if you're too busy, but yeah - that would be awesome. Odd how little information's out there on this topic. Not what I expected. A few support pages and a handful of dudes on Youtube - that's pretty much it.



Cool. I’d been planning on this last fall, but had sort of let the idea slide because of various issues, including the ongoing questions about whether Lemur is still going to be supported going forward. But this makes me think that I should perhaps still do so.

About those ongoing support questions, I personally find Lemur essential enough to my workflow that I would be more than willing to pay again for a “Lemur 2.0” new version that updates said support to the latest versions of iOS, fixes the main bugs and hopefully adds at least a few new features, if that is what Liine would need to make continued support of the product viable. Certainly that’s what many other iOS app makers do to sustain their businesses.


----------



## quickbrownf0x (Feb 3, 2019)

Nice! Yeah, same here. 

Hey, does anybody know how to go about doing this in the Project Logical Editor (by any chance?); 

- select and toggle subfolder "X" where the parent folder is "Y". 

I'm about to poke my eyes out with a rusty fork.


----------



## tapewtelve (Mar 16, 2021)

I was trying to do the same but failed, then followed some of the advice on here. Great job it is, so thanks for that.

Ive a further question that (if it's possible) will make it quicker to do this, and possibly a way for you guys to improve the efficiency at which you can create new templates.

Can you rename containers programatically? The manual says for a few components under the 'name' variable, that the attribute is 'get object name only', but for all others (including Container) its says 'Object name'.

I tried changing the name with setattribute(<Container>, 'name', '<NEW_NAME>'), but it doesnt work.

Am i wrong, or is the manual wrong?


Bit of backgtound as to why i want to do this:

I have a container where i store parameter names and details like cc number, cc value, min/max values etc so that when i add a new custom component (a fader, or knob), and name its container correctly, it pulls all the details from the coresponding details container of the same name and sets all of the appropriate ctlout, mid messages etc. 

This requires me to change the name of each fader/knob's container to the same name as the container i wanna pull the midi settings from. Which, for all the machines i am planning to use this template on, will be a nightmare to do.

I basically want to have a script that iterates through all the faders/knobs, and renames all their containers to the the same as the details/settings continers i have.

This is currently to have full control over the TC Electronic M-One XL, so if anyone fancies it, i can throw it up here when im done.


----------



## pmcrockett (Mar 16, 2021)

tapewtelve said:


> I was trying to do the same but failed, then followed some of the advice on here. Great job it is, so thanks for that.
> 
> Ive a further question that (if it's possible) will make it quicker to do this, and possibly a way for you guys to improve the efficiency at which you can create new templates.
> 
> ...


I don't think it's possible to rename objects via code. Your best bet, if I'm understanding what you're aiming to do, may be to name all your containers the same thing with a number extension so they can be easily searched like I mentioned upthread, and then give each container an expression that holds the actual name of the container. Since that expression could be modified by code, you could use it instead of the name attribute. If you needed to find a specific container, you'd just search all the containers until you found the matching expression.


----------



## tapewtelve (Mar 16, 2021)

pmcrockett said:


> I don't think it's possible to rename objects via code. Your best bet, if I'm understanding what you're aiming to do, may be to name all your containers the same thing with a number extension so they can be easily searched like I mentioned upthread, and then give each container an expression that holds the actual name of the container. Since that expression could be modified by code, you could use it instead of the name attribute. If you needed to find a specific container, you'd just search all the containers until you found the matching expression.


Ah yeah i was gonna do that, and it seems like its my best option since renaming isnt possible. 

Just thought itd be an expensive operation to iterate through everything and query its "title" expression to find what i want, instead of using findobject(). Then again, thats possibly what findobject() actually does.

Thanks for clarifying, i think ill take your advice.


----------

