Help with creating a Layout Group

If you are familiar with “Layout Group”  in Unity or “stack view” in IOS then you understand what I want to achieve, if not, then it’s basically a group that arranges its objects horizontally for example side by side based on their number and with. It also edits each object’s width based on it.

Here is the code I have:

function horizontalLayout( offset,x,y ) local group = display.newGroup( ) group.children = {} function group.sort(  ) local newOffset = x for i=1, #group.children do local child = group.children[i] child.x = newOffset child.y = y newOffset = newOffset + child.width + offset  end end function group.add( obj ) group:insert( obj ) group.children[#group.children+1] = obj group.sort() end return group end

This works as it should. The only problem is that it positions the objects from the starting point onwards, while a proper Layout Group should sort the objects based on their collective width extending in both directions. 

Example: If the starting x position = 150 and there are 2 objects in the group, then the first one should be positioned at (150 - object.width/2 - offset) and the second object should be the opposite. If there are 3 objects then the second object would be at exactly 150( I think), the first object on its left and the third object on its right.

The problem is that I’m unable to come up with the equation that achieves’s this kind of sorting.

I hope that I have described everything as clearly as possible.

Bear in mind that 0,0 is the centre of any display group and the width of a group is the total width of it’s content. This means that if you have a square which is only 10x10 placed at 0,100 inside the group, that group is 10 wide. You need to ensure that either everything in the group is centred at 0,0 or the top/left is placed along 0,0.

@Abdo23:

Give this modified code a try (just paste it into a main.lua and run it). I think it achieves what you’re looking for:

function horizontalLayout( offset, x, y ) local group = display.newGroup() group.children = {} group.anchorChildren = true function group.sort() for i=1, #group.children do local child = group.children[i] child.anchorX = 0 local last\_child = group.children[i - 1] or {x = offset, width = 0} child.x = last\_child.x + last\_child.width + offset child.y = 0 end group.anchorChildren = true end function group.add( obj ) group:insert( obj ) group.children[#group.children+1] = obj group.sort() end group.x, group.y = x, y return group end local test = horizontalLayout(20, display.contentCenterX, display.contentCenterY) local function add\_new\_rect() local rect = display.newRect(0, 0, 40, 40) rect:setFillColor(math.random(), math.random(), math.random()) test.add(rect) end timer.performWithDelay(1000, add\_new\_rect, 0)

This code works, But the main problem still exists, which is I don’t want to manipulate the position of the group. I need to sort the children without modifying group(x,y) 
The positions of the children should be independent of the position of the group.

Hi.

I wrote this module for my own needs, which lets me arrange objects relative to one another within the same group (should handle groups sharing a corner, too). I’m even using it in the stuff I’m working on at the moment. Basic usage goes something like:

local layout = require("layout") local my\_group = display.newGroup() local obj1 = NewObject(my\_group) local obj2 = AnotherObject(my\_group) local obj3 = YetAnotherObject(my\_group) layout.PutRightOf(obj1, 50) -- content x... layout.PutBelow(obj1, 50) -- ...and y layout.PutRightOf(obj2, obj1, 10) -- put object #2 to the right of object #1, 10 pixels past its right edge layout.PutRightOf(obj3, obj2, 10) -- ditto with object #3, relative to #2 layout.TopAlignWith(obj2, obj1) -- line them up vertically layout.TopAlignWith(obj3, obj1)

For more elaborate needs, something else I’ve been meaning to try is amoeba, by the same author of the library used by Corona’s UTF-8 plugin. By the looks of it, the Lua “binding” it provides is just an alternative to the C version, but I haven’t dug in too deep to be sure.

@abdo23:

I’m a bit confused about your goals here. If the position of the children should be independent of the position of the group, then why bother putting them into a separate group at all? You can just as easily track them in a table and position them inside the current scene’s view (if you’re using composer) or in the global display canvas.

But the code I provided allows you to sort the children without modifying group.x and group.y - you can just set those values once, to define where you want the sorted objects to be centered (or left-justified, or right-justified, etc.). Future sort calls will just rearrange the nested objects, without needing to reposition the parent group.

I think I may have misunderstood your goals here. Please elaborate on what specifically you want to accomplish and hopefully we can arrive at a solution - you’ve got Matt (@horacebury) and Steve (@starcrunch) on this thread, so you’re already in a privileged position. They’re crazy good at these sorts of problems. :smiley:

Abdo you mean this feature of Unity right?

https://docs.unity3d.com/Manual/script-HorizontalLayoutGroup.html

This video shows the control at 5:55

http://www.youtube.com/watch?v=DAdW_K44Dao&t=5m55s

Tip: For the best help, provide as much information as you can to the folks who will answer.

I found this info in about a minute of searching. (Then I had to spend about 10 minutes watching the video and dtermining the proper watch time  for the link above).  I think, if you had provided this info you would have an answer now.

You need to remember, most of us are super busy, so we (I do this a lot) do our best to guess what the OP is asking after a partial or at most a single reading.

Only some will take the time to research the question.  Why?  Because the OP should have done it and provided that research in the question.  

This often causes a total disconnect between the answers given and the OP’s actual needs.

I say it all the time, but people asking questions should put in a lot more effort asking their question than the answering parties spend.  (2x or 3x at a bare minimum)

Anyways, If nobody answers now that they know what this is, exactly.  I will answer Friday.

Hm so it’s something like this?

The code rescales the children with respect of all it’s siblings sizes while it keeps the offset unscaled.

function horizontalLayout( offset, x, y, w, h ) local group = display.newGroup() group.bgRect = display.newRect( group, 0, 0, w, h ) group.bgRect.anchorX = 0 group.bgRect.anchorY = 0 group.children = {} group.x = x group.y = y function group.sort() local numChildren = #group.children local unscaledWidth = 0 for i = 1, numChildren do unscaledWidth = unscaledWidth + group.children[i].originalWidth end local scaledWidth = w - (1+numChildren)\*offset local scaleX = scaledWidth / unscaledWidth local nextChildX = offset for i=1, #group.children do local child = group.children[i] child.width = child.originalWidth \* scaleX child.height = h - 2\*offset child.x = nextChildX child.y = offset nextChildX = nextChildX + child.width + offset end end function group.add( obj ) group:insert( obj ) group.children[#group.children+1] = obj obj.anchorX = 0 obj.anchorY = 0 obj.originalWidth = obj.width obj.originalHeight = obj.height group.sort() end function group.setDim( newW, newH ) w = newW h = newH group.bgRect.width = w group.bgRect.height = h group.sort() end group.x, group.y = x, y return group end local x = 300 local y = 200 local test = horizontalLayout( 10, x, y, 300, 100 ) local function add\_new\_rect() local rect = display.newRect(0, 0, math.random(10, 50), 40) rect:setFillColor(math.random(), math.random(), math.random()) test.add(rect) end for i = 1, 5 do add\_new\_rect() end function resizeGroup() test.setDim( 200+(1+math.sin(system.getTimer()\*0.0005))\*300, 100 ) end timer.performWithDelay(10, resizeGroup, 0)

It seems that due to some poor explanation of the problem and miscommunication on my part, you guys don’t get exactly what I want to achieve here and that is completely my fault.
Anyways, I’ve decided to approach the problem in a completely different way. Thank you to anyone who tried to help, and my apologise to you If I’ve wasted your time.

So, the OP was not about replicating this feature of Unity?: https://docs.unity3d.com/Manual/script-HorizontalLayoutGroup.html

Bear in mind that 0,0 is the centre of any display group and the width of a group is the total width of it’s content. This means that if you have a square which is only 10x10 placed at 0,100 inside the group, that group is 10 wide. You need to ensure that either everything in the group is centred at 0,0 or the top/left is placed along 0,0.

@Abdo23:

Give this modified code a try (just paste it into a main.lua and run it). I think it achieves what you’re looking for:

function horizontalLayout( offset, x, y ) local group = display.newGroup() group.children = {} group.anchorChildren = true function group.sort() for i=1, #group.children do local child = group.children[i] child.anchorX = 0 local last\_child = group.children[i - 1] or {x = offset, width = 0} child.x = last\_child.x + last\_child.width + offset child.y = 0 end group.anchorChildren = true end function group.add( obj ) group:insert( obj ) group.children[#group.children+1] = obj group.sort() end group.x, group.y = x, y return group end local test = horizontalLayout(20, display.contentCenterX, display.contentCenterY) local function add\_new\_rect() local rect = display.newRect(0, 0, 40, 40) rect:setFillColor(math.random(), math.random(), math.random()) test.add(rect) end timer.performWithDelay(1000, add\_new\_rect, 0)

This code works, But the main problem still exists, which is I don’t want to manipulate the position of the group. I need to sort the children without modifying group(x,y) 
The positions of the children should be independent of the position of the group.

Hi.

I wrote this module for my own needs, which lets me arrange objects relative to one another within the same group (should handle groups sharing a corner, too). I’m even using it in the stuff I’m working on at the moment. Basic usage goes something like:

local layout = require("layout") local my\_group = display.newGroup() local obj1 = NewObject(my\_group) local obj2 = AnotherObject(my\_group) local obj3 = YetAnotherObject(my\_group) layout.PutRightOf(obj1, 50) -- content x... layout.PutBelow(obj1, 50) -- ...and y layout.PutRightOf(obj2, obj1, 10) -- put object #2 to the right of object #1, 10 pixels past its right edge layout.PutRightOf(obj3, obj2, 10) -- ditto with object #3, relative to #2 layout.TopAlignWith(obj2, obj1) -- line them up vertically layout.TopAlignWith(obj3, obj1)

For more elaborate needs, something else I’ve been meaning to try is amoeba, by the same author of the library used by Corona’s UTF-8 plugin. By the looks of it, the Lua “binding” it provides is just an alternative to the C version, but I haven’t dug in too deep to be sure.

@abdo23:

I’m a bit confused about your goals here. If the position of the children should be independent of the position of the group, then why bother putting them into a separate group at all? You can just as easily track them in a table and position them inside the current scene’s view (if you’re using composer) or in the global display canvas.

But the code I provided allows you to sort the children without modifying group.x and group.y - you can just set those values once, to define where you want the sorted objects to be centered (or left-justified, or right-justified, etc.). Future sort calls will just rearrange the nested objects, without needing to reposition the parent group.

I think I may have misunderstood your goals here. Please elaborate on what specifically you want to accomplish and hopefully we can arrive at a solution - you’ve got Matt (@horacebury) and Steve (@starcrunch) on this thread, so you’re already in a privileged position. They’re crazy good at these sorts of problems. :smiley:

Abdo you mean this feature of Unity right?

https://docs.unity3d.com/Manual/script-HorizontalLayoutGroup.html

This video shows the control at 5:55

http://www.youtube.com/watch?v=DAdW_K44Dao&t=5m55s

Tip: For the best help, provide as much information as you can to the folks who will answer.

I found this info in about a minute of searching. (Then I had to spend about 10 minutes watching the video and dtermining the proper watch time  for the link above).  I think, if you had provided this info you would have an answer now.

You need to remember, most of us are super busy, so we (I do this a lot) do our best to guess what the OP is asking after a partial or at most a single reading.

Only some will take the time to research the question.  Why?  Because the OP should have done it and provided that research in the question.  

This often causes a total disconnect between the answers given and the OP’s actual needs.

I say it all the time, but people asking questions should put in a lot more effort asking their question than the answering parties spend.  (2x or 3x at a bare minimum)

Anyways, If nobody answers now that they know what this is, exactly.  I will answer Friday.

Hm so it’s something like this?

The code rescales the children with respect of all it’s siblings sizes while it keeps the offset unscaled.

function horizontalLayout( offset, x, y, w, h ) local group = display.newGroup() group.bgRect = display.newRect( group, 0, 0, w, h ) group.bgRect.anchorX = 0 group.bgRect.anchorY = 0 group.children = {} group.x = x group.y = y function group.sort() local numChildren = #group.children local unscaledWidth = 0 for i = 1, numChildren do unscaledWidth = unscaledWidth + group.children[i].originalWidth end local scaledWidth = w - (1+numChildren)\*offset local scaleX = scaledWidth / unscaledWidth local nextChildX = offset for i=1, #group.children do local child = group.children[i] child.width = child.originalWidth \* scaleX child.height = h - 2\*offset child.x = nextChildX child.y = offset nextChildX = nextChildX + child.width + offset end end function group.add( obj ) group:insert( obj ) group.children[#group.children+1] = obj obj.anchorX = 0 obj.anchorY = 0 obj.originalWidth = obj.width obj.originalHeight = obj.height group.sort() end function group.setDim( newW, newH ) w = newW h = newH group.bgRect.width = w group.bgRect.height = h group.sort() end group.x, group.y = x, y return group end local x = 300 local y = 200 local test = horizontalLayout( 10, x, y, 300, 100 ) local function add\_new\_rect() local rect = display.newRect(0, 0, math.random(10, 50), 40) rect:setFillColor(math.random(), math.random(), math.random()) test.add(rect) end for i = 1, 5 do add\_new\_rect() end function resizeGroup() test.setDim( 200+(1+math.sin(system.getTimer()\*0.0005))\*300, 100 ) end timer.performWithDelay(10, resizeGroup, 0)

It seems that due to some poor explanation of the problem and miscommunication on my part, you guys don’t get exactly what I want to achieve here and that is completely my fault.
Anyways, I’ve decided to approach the problem in a completely different way. Thank you to anyone who tried to help, and my apologise to you If I’ve wasted your time.

So, the OP was not about replicating this feature of Unity?: https://docs.unity3d.com/Manual/script-HorizontalLayoutGroup.html