Page 1 of 2

multiple layertofronts behavior?

Posted: Fri Apr 10, 2015 6:08 pm
by Bugala
I have this simple subroutine which handles fixing cards in nice row.

In short it works so that i have handcards in table, say:

Code: Select all

t_handcards = { "c1", "c2", "c5"}
Those "c1" etc. are actual layer names used for the cards.

in this example, original hand had been c1 to c5, but now c3 and c4 have been discarded, leaving empty space in their place, and then i enter this hand into my subroutine which goes roughly:

Code: Select all

n=0
foreach(t_handcards, function(index, value)
                                                     layertofront(value)
                                                     movelayer(value, #USELAYERPOSITION, #USELAYERPOSITION, x + (spacebetweencards * n), y)
                                                     n=n + 1
                               endfunction)
(this example is forgetting that the index 0 is last one in queue, but in real version, this is considered too)

What I was expecting to happen, was that leftmost card would seemingly be beneath every other card, and right most card, would be the top card.

Since idea is that left most card is put into its place first, and moved to front, and right after the next card is moved to its place, and once again moved to front (making the previous card obviously not the front card anymore).


But now in practice i notice that while right most card correctly is always the top most card, the order of the rest of the cards is not as i expected, but it could be that from rest of the cards, for example middle one might be the one on top of every other card.

I thought layertofront works in such way, that say i have {a, b, c, d} layers in queue, and then i switch layer c to front, that now the table would look like {c, a, b, d}, but seems this is not the case, at least not after multiple layertofronts.

So how does this layertofront work the row? Does it swap their places, for example i switch c to front, and a moves to c:s place, or what?

Re: multiple layertofronts behavior?

Posted: Sat Apr 18, 2015 11:16 am
by airsoftsoftwair
No, LayerToFront() doesn't swap places. That's what SwapLayers() is for. LayerToFront() simply removes the layer from its position in the stack and inserts it at the top.

Re: multiple layertofronts behavior?

Posted: Fri Aug 18, 2017 7:17 pm
by Bugala
Now that I noticed I was encountering this same problem again, to make continuation question to your answer.

So say I have two layers. One in Z-pos 36 (top most layer) and one in Z-pos 20.

Now i use LayerToFront() for z-pos 20 layer and it becomes z-pos 36. But where does the previous Z-pos 36 go? For it seems there is some randomness to it.

Re: multiple layertofronts behavior?

Posted: Sat Aug 19, 2017 12:16 pm
by airsoftsoftwair
Bugala wrote:Now that I noticed I was encountering this same problem again, to make continuation question to your answer.

So say I have two layers. One in Z-pos 36 (top most layer) and one in Z-pos 20.

Now i use LayerToFront() for z-pos 20 layer and it becomes z-pos 36. But where does the previous Z-pos 36 go?
Well, one below the top z-position of course. Just use DumpLayers() to check.
For it seems there is some randomness to it.
Then you need to post a very small example program that proves this thesis...

Re: multiple layertofronts behavior?

Posted: Sat Aug 19, 2017 1:39 pm
by Bugala
you can try it with this:

Code: Select all

Function StartLayerToFront()
   SetInterval(1, MultipleLayerToFront, 1)
EndFunction


Function MultipleLayerToFront()
	If IsLeftMouse() = False Then ClearInterval(1)
	For n = 1 To 5
		LayerToFront("layer"..n)
	Next
EndFunction




EnableLayers

CreateLayer(100, 100, 200, 300, {Color = #RED, name="layer1"})
CreateLayer(200, 100, 200, 300, {Color = #GREEN, name="layer2"})
CreateLayer(300, 100, 200, 300, {Color = #BLUE, name="layer3"})
CreateLayer(400, 100, 200, 300, {Color = #YELLOW, name="layer4"})
CreateLayer(500, 100, 200, 300, {Color = #WHITE, name="layer5"})

For n = 1 To 5
	MakeButton(Nil, #LAYERBUTTON, "layer"..n, True, False, {OnMouseDown = StartLayerToFront})
Next

Repeat
WaitEvent()
Until quit = True

It seems to me problem is only with the one being replaced from the top position, rest stay in order they should.

Re: multiple layertofronts behavior?

Posted: Sat Aug 19, 2017 7:14 pm
by Bugala
Here is new and working version now:

Code: Select all

LayerGroup = { Groups = {} }


Function LayerGroup:New()
	Local d = {}
  
	SetMetaTable(d, self)
	self.__index = self

	Return(d)
EndFunction




Function LayerGroup:CreateGroup(GroupID, LayerID) /* is the first Layer, upon which rest will be relative to */
	self.Groups[GroupID] = {}
	self.Groups[GroupID][1] = LayerID
	Local t = GetLayerStyle(layerID)
	userdata = { originalposition = { x = t.x, y = t.y, w = t.width, h = t.height } }
	SetObjectData(#LAYER, LayerID, "userdata", userdata)
EndFunction



Function LayerGroup:DeleteGroup(GroupID)
	self.groups[GroupID] = Nil
EndFunction



Function LayerGroup:AddLayer(GroupID, ...) /* Each ... is LayerID to be added to the specified group */
	Local base_t = GetLayerStyle(LayerGroup.groups[GroupID][1]) /*Baselayers current stylesettings */
	Local userdata = GetObjectData(#LAYER, LayerGroup.groups[GroupID][1], "userdata")
	Local t_orig = userdata.originalposition
	Local origwidthmultiplier  = t_orig.w / base_t.width
	Local origheightmultiplier = t_orig.h / base_t.height

	For Local n = 0 To arg.n-1
		Local t = GetLayerStyle(arg[n])
		Local userdata = { 
				   originaldata = { x = (t.x - base_t.x) * origwidthmultiplier,   y = (t.y - base_t.y) * origheightmultiplier,   w = t.width * origwidthmultiplier,   h = t.height * Origheightmultiplier },  
		                   lastposition = { x = t.x,   y = t.y,   w = t.width,   h = t.height } 
		                 }
		SetObjectData(#LAYER, arg[n], "userdata", userdata)
		InsertItem(self.Groups[GroupID], arg[n])
	Next
EndFunction



Function LayerGroup:RemoveLayer(GroupID, ...) /* each ... is LayerID to be removed from specified Group */
	For Local n = 0 To arg.n-1
		Local found = -1
		ForEach(self.Groups[GroupID], Function (Index, LayerID)
							If arg[n] = LayerID Then found = Index
					      EndFunction) 
		If found <> -1 Then RemoveItem(self.Groups[GroupID], found)
	Next	
EndFunction



Function LayerGroup:ShowGroup(GroupID, Positiontable)
	Local baselayer = self.groups[GroupID][1]
	Local userdata = GetObjectData(#LAYER, baselayer, "userdata")
	baseorig = userdata.originalposition
	
	Local t = GetLayerStyle(baselayer)  /* Can use GetLayerStyle instead of userdata, because baselayer is always on round() pixels. */

	Local new_x = t.x
	Local new_y = t.y
	Local new_w = t.width
	Local new_h = t.height
	
	If HaveItem(Positiontable, "x") Then new_x = Positiontable.x
	If HaveItem(Positiontable, "y") Then new_y = Positiontable.y
	If HaveItem(Positiontable, "w") Then new_w = Positiontable.w
	If HaveItem(Positiontable, "h") Then new_h = Positiontable.h

	SetLayerStyle(baselayer, { x = new_x, y = new_y, width = new_w, height = new_h } )

	widthmultiplier  = new_w / baseorig.w
	heightmultiplier = new_h / baseorig.h

	Local changedpositionlist = {}
	
	ForEach(self.groups[GroupID], Function (index, layerID)
		If layerID <> baselayer
			Local t = GetLayerStyle(LayerID)
			Local userdata = GetObjectData(#LAYER, layerID, "userdata")
			Local lastposition = userdata.lastposition
			If t.x <> lastposition.x Or t.y <> lastposition.y Or t.width  <> lastposition.w Or  t.height <> lastposition.h  Then InsertItem(changedpositionlist, layerID)	 
		EndIf
				      EndFunction)


	ForEach(changedpositionlist, Function (index, layerID)
			LayerGroup:RemoveLayer(GroupID, layerID)
			LayerGroup:AddLayer(GroupID, layerID)
			     EndFunction)

		
	ForEach(self.groups[GroupID], Function (index, layerID)
			If layerID <> baselayer
			  Local userdata = GetObjectData(#LAYER, layerID, "userdata")
			  Local orig_t = userdata.originaldata
			  
			  Local xpos = new_x + ( orig_t.x * widthmultiplier  )
			  Local ypos = new_y + ( orig_t.y * heightmultiplier )
			  Local wpos = orig_t.w * widthmultiplier
			  Local hpos = orig_t.h * heightmultiplier
			  SetLayerStyle(LayerID, {  x = xpos,  y = ypos,  width = wpos,   height = hpos} )
			  Local temp = GetLayerStyle(LayerID)
			  Local lastposition = { x = temp.x, y = temp.y, w = temp.width, h = temp.height }
			  userdata.lastposition = lastposition
			  SetObjectData(#LAYER, layerID, "userdata", userdata)
			EndIf
				      EndFunction)		
EndFunction
I havent fully tested this. I do know if you form a group and then move them, that it will work just fine.

However, if you move one of them independently and then do the group move again I havent properly tested, maybe works, maybe wont.

Re: multiple layertofronts behavior?

Posted: Sat Aug 19, 2017 9:09 pm
by Bugala
Forget the post above this one, i meant that to other place in forum.

Re: multiple layertofronts behavior?

Posted: Sun Aug 27, 2017 5:36 pm
by Bugala
Adding to the multiplelayertofront problem behavior some new info I just noticed.

By the way, you did notice i posted three posts above this an example where the layertofront behaves wrong?

I just noticed that it seems like the problem isnt actually to do with the layer positioning necessarily, but with graphics positioning.

For moment ago I was able to click on a layerbutton that was behind another layer button. And the point is, if graphics had updated correctly, then that layers graphics should have been on top of the other layers graphics, meaning that basically the buttons behavior was correct, although graphics were showing different.

Re: multiple layertofronts behavior?

Posted: Tue Aug 29, 2017 5:37 pm
by airsoftsoftwair
Yes, I saw that example but it makes me dizzy :) Please try to come up with something that is easier to understand and you also have to describe in detail what is the expected result and what is the actual result. But the code is very weird to say the least....

Re: multiple layertofronts behavior?

Posted: Tue Aug 29, 2017 8:28 pm
by Bugala
I think you are looking at wrong code, you are probably looking the one i accidentally posted which was meant for other part of forum.

Heres the right example code again:

Code: Select all

Function StartLayerToFront()
   SetInterval(1, MultipleLayerToFront, 1)
EndFunction


Function MultipleLayerToFront()
   If IsLeftMouse() = False Then ClearInterval(1)
   For n = 1 To 5
      LayerToFront("layer"..n)
   Next
EndFunction




EnableLayers

CreateLayer(100, 100, 200, 300, {Color = #RED, name="layer1"})
CreateLayer(200, 100, 200, 300, {Color = #GREEN, name="layer2"})
CreateLayer(300, 100, 200, 300, {Color = #BLUE, name="layer3"})
CreateLayer(400, 100, 200, 300, {Color = #YELLOW, name="layer4"})
CreateLayer(500, 100, 200, 300, {Color = #WHITE, name="layer5"})

For n = 1 To 5
   MakeButton(Nil, #LAYERBUTTON, "layer"..n, True, False, {OnMouseDown = StartLayerToFront})
Next

Repeat
WaitEvent()
Until quit = True
In case you really are feeling dizzy about this code, then let me cut it down to pieces to understand what is important what is not:

Code: Select all

EnableLayers

CreateLayer(100, 100, 200, 300, {Color = #RED, name="layer1"})
CreateLayer(200, 100, 200, 300, {Color = #GREEN, name="layer2"})
CreateLayer(300, 100, 200, 300, {Color = #BLUE, name="layer3"})
CreateLayer(400, 100, 200, 300, {Color = #YELLOW, name="layer4"})
CreateLayer(500, 100, 200, 300, {Color = #WHITE, name="layer5"})

For n = 1 To 5
   MakeButton(Nil, #LAYERBUTTON, "layer"..n, True, False, {OnMouseDown = StartLayerToFront})
Next

Repeat
WaitEvent()
Until quit = True
This is simply creating 5 layer boxes, each one is partially overlapping another box (to demonstrate the problem).

Then each layer is made into a button. They all do the exact same thing, which is to call the "StartLayerToFront()" function when pushing left mouse button down.

Code: Select all

]Function StartLayerToFront()
   SetInterval(1, MultipleLayerToFront, 1)
EndFunction
This is simply using setinterval so that the function would be repeatedly being executed until you release left mouse button.

Code: Select all

Function MultipleLayerToFront()
   If IsLeftMouse() = False Then ClearInterval(1)
   For n = 1 To 5
      LayerToFront("layer"..n)
   Next
EndFunction
And this is whichj causes the bug to happen.

Each layer is put being the top most in order. First the box number 1, then number 2, then number 3.

What I expect to be the result is that box number 1 would be the bottom most box, and number 5 would be the top most, and every number between in that order. As example, number 2 should be below number 3, and number 4 should be on top of 3.

However, in practice by starting this small piece of code, and pushing left mouse button down on top of any of those boxes and releasing the left mouse button, you can see that most of time the z-order of boxes is wrong. Only rarely does it actually end to 1, 2, 3, 4, 5 order as it should, but rather it could be 1, 4, 2, 3, 5 as example.

However, interestingly even if one of the box layers is completely covered by other button layers, it is however still activating the layer button that it should, if the graphics would be showing right. This behavior however cant be tested with this piece of code, I am mentioning that only as extra info.