[Solved]Need help with modifying the viewbuilder after regeneration

Hi there, i’m working on a very personally oriented tool to control a Fostex VM200 mixer.
This mixer is only “mono” inputs but permit to “pair” channels to form a stereo one.
So in that case i want to modify the view according to “paired groups” variables.

In the following picture, you can see groups 17+18 and 19+20 are paired and the gear “slices” get closer. (this is the default configuration, vb is build on tool starting).
1st%20build
The view with the faders is named “gear_view” and is an unique child of its parent “gear_frame”.

I added an “update_gear_frame” that is invoked on changing the “paired groups” variables (from the down right buttons:
First try to remove the gear-view:
local function update_gear_frame()
gear_frame:remove_child(gear_view)
end

Result is the next picture: it did what i ask…
child%20removed

Then i added more in the update function like this:
local function update_gear_frame()
gear_frame:remove_child(gear_view)
gear_panel()
gear_frame:add_child(gear_view)
end

(the gear_panel() function is the function that build the view “gear_view”)

The result is the next picture:
child%20added%20again

I understand that the gear_view is removed but not cleared, and i add more childs to it with the gear_panel() function. The newly added ones fit my needs (you can see channels “1+2” are closer on the second generation).
I tried to add a “gear_view = nil” like this:
local function update_gear_frame()
gear_frame:remove_child(gear_view)
gear_view = nil
gear_panel()
gear_frame:add_child(gear_view)
end

Found that on a very old topic…but i got this error:
"attempt to index upvalue ‘gear_view’ (a nil value)
which also makes sense…

Do anybody have an advice or a trick to refresh my “gear_view” in a proper way?
Thanks ahead!!!

1 Like

I think I understand what happens to you. I don’t know your code, but it focuses on the “envelopes” you are using, such as row, column, horizontal_aligner or vertical_aligner. These “envelopes” we use to enclose objects, such as buttons and others.

A property of these “envelopes” is the “height”. Each time you add an object inside, “height” will change in value, or there will be some envelope enclosed within another, even if you don’t define it. So, if you delete a child, but not its envelope, this envelope will still have the value of height. Therefore, you must make sure to remove the child with its envelope. For example:

vb:row{
  id="MAIN_ROW",
  vb:row{
    id="CHILD_ROW",
    vb:buton{
      id="BUTTON_1"
    }
  }
}

If you remove:

vb.views.CHILD_ROW:remove_child(vb.views.BUTTON_1) the height of CHILD_ROW will continue to prevail over MAIN_ROW. Then, you will see a blank space, as happens to you.

To leave no trace, better this:
vb.views.MAIN_ROW:remove_child(vb.views.CHILD_ROW)

In summary, remove the child with remove_child() without leaving a trace of another element that has its own height, such as a row or column.

Hi Raul,
thanks for your help…but i’m not sure i explained properly my case.

In the second picture of my first topic, the blank space after removing the content is ok for me, as i want to fill it right after with the new “gear_view” child.
In other worlds, if you look at the 3rd picture, i want to replace the 21 first left “fader slices” by the 21 last right “fader slices”, and not accumulating them.
The result should be as on the first picture.

I’m sorry if i’m not clear at all, my english sucks, and makes hard for me to explain my thoughs…
Maybe i need to build different views for all possible paired channels.
For example focusing only on channels 1 & 2; if i build 3 vb column as for “channel1” (not paired)," channel2" (not paired), and “channel1+2” (paired).
Then i add them all to the parent view, and:

  • if they are really paired i “hide” the “channel1” & " channel2" views.
  • if they are not, i hide the “channel1+2” view.

What do you think ? How you’ll manage that case ?
Thanks.

In general you have 2 ways to “hide” items (hide, displace):

  1. Use the visible = false property, for a surround view (column, or row). With an iteration function you can hide several similar elements at once. Use the “id” with some linear number to iterate.
  2. Use the negative spacing property (spacing = -1 or less). This way you can scroll horizontally if you use a parent or vertical row if you use a parent column. To do this try the following:
vb:row{
  spacing= -50, --negative value
  vb:row{},  --this row (or other item) will allow the next row to move 50 pixels to the left.
  vb:row{
    id="MAIN_ROW",
    vb:row{
      id="RW_1"
    },
    vb:row{
      id="RW_2"
    },
    vb:row{
      id="RW_3"
    },
  }
}

This setting will allow you to move the row with id=“MAIN_ROW” to the left (or to the right if you increase the value), including all its content (RW_1, RW_2, RW_3).

You can do the same with columns, vertically, moving up or down.

So you can play with 3 things:

  1. Hide the [visible = false / true] element.
  2. Move the element (therefore hidden) [spacing = -X or + X].
  3. Remove the item (not equal to null), it will not be seen in the view, so you can retrieve it later. This also hides the element, but still exists [remove_child () and add_child ()].

First let me say that, without seeing and deep diving the full code, it’s often a bit tricky to help in these matters since you can structure the code in many ways.

That being said, I think there is an obvious scope error in this code:

local function update_gear_frame()
gear_frame:remove_child(gear_view)
gear_view = nil
gear_panel()
gear_frame:add_child(gear_view)
end

If you set a gear_view variable within gear_panel(), it will not be in the same scope as your update_gear_frame(). And if you tried to have it be a global variable, you would mess it up when nullifying it. Have you tried it like this?

local function update_gear_frame()
gear_frame:remove_child(vb.views.gear_view)  -- id = "gear_view" should be set on your top rack view.
vb.views.gear_view = nil
local gear_view = gear_panel()
gear_frame:add_child(gear_view)
end

Also make sure that gear_panel() returns gear_view, by ending the function with “return gear_view”.

The nil assignment ‘trick’ is meant for clearing views that are referenced inside vb.views, so I think there is a slight misunderstanding there.

… Well, that’s just a few pointers.

PS. It’s not the fault of LUA or the API that these things are a bit clumsy to work with. IMO, once you start structure your code with classes, it will become much easier to wrap your head around the code and avoid scope issues. No more unnecessary global variables or relying on passing ugly tables and variables from function to function :wink:

i just want to chime in to say that the layout mixer with big faders looks awesome… i would love to have that in renoise as well :stuck_out_tongue:

One more comment, and you choose. I suggest that you use visible = false as far as possible, and forget about remove_child(), add_child().

With the property visible=false, the racks (row or column) will remain in their position, but hidden. If you use remove_child(), add_child(), you are probably generating an accumulation of racks, if they are consecutive racks (you have to know what you are doing). With remove_child() you will lose your position, unless your parent rack has no other elements, otherwise you will be shifting position when using add_child() again, unless you have it structured in another way to avoid precisely this.

The “visible” property works extraordinarily well, even if you use hundreds of racks. With remove_child() add_child() you must know how it works to use it correctly. For example, you can use remove_child() to remove a parent rack that has many child racks. If you don’t cancel it, that rack will still exist. Therefore, you can add it with add_child in another rack container, somewhere else. So you can work with all that.

Don’t do that. It’s just bad practice. Objects should be removed and garbage collected by Renoise?

It’s not difficult to do it properly. Use a rack with an id as container, use remove/add_child and the nil assignment before rebuilding and readding.

Joule, “as far as possible.”
If you have to recover the same thing you had before, using visible property is a completely correct approach. There is no problem at all.

Objects can be removed when necessary. But it is not always necessary. It depends on what you want to do with your objects. In fact, in many cases it is not necessary. And in certain cases it is not necessary to do “= nil” if you are going to recover it later or change position (elsewhere in the view).

1 Like

Hi guys,
sorry i was little very busy at work, but i did try some of your advices., and thank you both Raul and joule for those.
I prefer to stay on the remove / add child method, because i don’t want to " recover the same thing i had before" (as you said Raul).
The real problem i had should have been with some syntax, i don’t really know, but rearranging my code and rewriting some parts of it did fix the mistake…
I have my viewbuilder refreshing as i needed now, so i can go further with other functions of my tool…

One last mystery here…

for any reason, this code gave me an error that “gear_view” was not declared or found nil…
but making it like this directly:

local function update_gear_frame()
gear_frame:remove_child(vb.views.gear_view)
vb.views.gear_view = nil
gear_frame:add_child(gear_panel() )
end

made it work.
Thank you anyway to both of you. I know i need to improve my coding knowledge, as i’m not a programmer in the blood, but i need to force myself to it because i need tools to interact with my hardware as a musician. I hope to not bother you too much in the future…
Thanks again!!

Those two snippets should do exactly the same, so the difference must have been something else.