Datawindow dragdrop event doesn't always return a reference to the control at the drop location - powerbuilder

In short, I need to base some window behavior on the type of object a control is dropped on, after being dragged. This is all well and good as long as the target control at the destination is a column, but not if it is any other object.
Assume I have a datawindow with two columns, and a rectangle. Let's call them c_1, c_2, and r_1, respectively.
I drag c_1 and drop it on c_2:
dwo.name = c_2
dwo.type = column
This is fine, and exactly the behavior I expect.
I drag c_1 and drop it on r_1:
dwo.name = datawindow
dwo.type = datawindow
A reference to the datawindow itself is returned. This is too broad to use as a basis for building anything meaningful, at least in my case.
In testing, it seems that I can't make dragdrop return a reference to the control at the drop location unless it is a column. Is this intended, or is something going wrong in my environment? How can I work around this if I need to base window behavior on the value of dwo.type or dwo.name?

Use the function GetObjectAtPointer
It will allow you to know exactly what object the user dropped something onto.
It returns a string of the form objectname~trow that you have to parse to identify what you need.

One approach would be to check the X and Y coordinates of the pointer against the array of controls within the datawindow.
Within an event on the datawindow you could get the list of objects like this:
is_selected_controls = is_null //both of these are string arrays
ls_objects = this.Describe( 'DataWindow.Objects')
ls_objects = ls_objects + '~t'
ll_pos = pos(ls_objects, '~t')
ll_orig_pos = 1
Then loop through the array and get each controls X, W, Width, Height
DO WHILE ll_pos > 0
ls_object = mid(ls_objects, ll_orig_pos, ll_pos -ll_orig_pos)
IF describe(ls_object + '.type') = 'line' THEN
ls_x = this.Describe(ls_object + '.X1')
ls_y = this.Describe(ls_object + '.Y1')
ls_h = this.Describe(ls_object + '.Y2')
ls_w = this.Describe(ls_object + '.X2')
ELSE
ls_x = this.Describe(ls_object + '.X')
ls_y = this.Describe(ls_object + '.Y')
ls_h = this.Describe(ls_object + '.height')
ls_w = this.Describe(ls_object + '.width')
END IF
// compare the X,Y of the pointer to control position to see if it's
// on the control, if it is exit the loop and do whatever...
ll_orig_pos = ll_pos + 1
ll_pos = pos(ls_objects, '~t', ll_orig_pos)
LOOP

Related

x and y get added additional value after setting Transform()

I am working on svg free transform. Everything works fine except if the object has its own transform attribute with scale value after page initialed.
Something like this:
<g transform="matrix(1.5,0,0,1.5,70,70)"></g>
Here is what I do to dragging and resizing this object
var newTransform = 't' + (this.data('xy').x) + ',' + (this.data('xy').y);
newTransform += 'r' + (this.data('r'))
newTransform += 's' + (this.data('s'))
this.transform(newTransform);
If the object has no initial scale value, this works fine as except. The object can be dragged and scaled perfectly.
But, if the object has scale attribute(not equal to 1) at the beginning, when I set the first transform(), the object will be scaled again. Additional x,y and size will be added. If I use matrix instead, the problem can be solved. But the object won't scale from center.
Transform with matrix:
var t = new Snap.Matrix()
t.add(this.data('s'),0,0,this.data('s'),this.data('xy').x,this.data('xy').y);
this.transform(t);
Am I doing something wrong on transform with snap svg string? How do I prevent from scale twice for the first transform(str)?
This can get quite complex. The simplest way if it can be incorporated, is to place the element to drag inside a g/group element. Then place the drag on that outer g/group element.
This keeps the existing transformation on the inner element in place, and doesn't get messy. So if you can include an extra group element into the svg, I would go this route.
If you can't for whatever reason. I think longer term (especially if you will be doing a freetransform including dynamic rotations etc), then I think you need to get a lot more complicated. I'm including a starting route I would possibly use, that will also be able to cope with a scaled viewbox/screen as well, as this introduces extra complexity.
So I would possibly introduce a couple of new methods...
getCursorPoint gets a real point of a mouse, accounting for any transformations on the screen (as opposed to the element). I'm not sure you need this in your specific example yet, but you may find you hit this problem later with a zoomed in paper or something.
getTransformedDrag, accounts for any screen transformations when dragging.
Element.prototype.getCursorPoint = function( x, y ) {
var pt = this.paper.node.createSVGPoint();
pt.x = x; pt.y = y;
return pt.matrixTransform( this.paper.node.getScreenCTM().inverse() );
}
Element.prototype.getTransformedDrag = function( otx, oty, x, y ) {
var xy = this.getCursorPoint( x, y );
var tdx = {};
var snapInvMatrix = this.data('origTransform').invert();
snapInvMatrix.e = snapInvMatrix.f = 0;
tdx.x = snapInvMatrix.x( xy.x - otx, xy.y - oty );
tdx.y = snapInvMatrix.y( xy.x - otx, xy.y - oty );
return tdx;
}
Now we've got a bit of background fluff around dragging out of the way, we can plug those in to some element dragging....
Store the possibly screen transformed cursor positions and the initial matrix on the element.
var dragStart = function(x, y, ev) {
this.data('origTransform', this.transform().localMatrix)
var txy = this.getCursorPoint(x,y)
this.data('oxy', {x: txy.x, y: txy.y });
}
var dragMove = function(dx, dy, x, y, ev) {
var tdr = this.getTransformedDrag( this.data('oxy').x, this.data('oxy').y, x, y)
this.data('xy', {
x: tdr.x,
y: tdr.y
})
.updateTransform();
}
Element.prototype.updateTransform = function() {
var newTransform = 't' + (this.data('xy').x) + ',' + (this.data('xy').y);
//newTransform += 'r' + (this.data('r'))
//newTransform += 's' + (this.data('s'))
this.transform(this.data('origTransform').toTransformString() + newTransform )
return this;
}
Example jsfiddle
As mentioned, this may seem overly complex, but I'm just trying to include some extra code you may find useful later, as it's quite a complex area. So just use this as a reference when you need it.

Fabricjs move object to layer

I am trying to move items to a different layer (so I can order them)
for (var x = 0; x < resp.Items.length; x++) {
$('#inv' + resp.Items[x].Type).attr('src', '/public/items/universe/' + resp.Items[x].Type + '/' + resp.Items[x].Name + '.png');
fabric.Image.fromURL('/public/items/universe/' + resp.Items[x].Type + '/' + resp.Items[x].Name + '.png', function(obj) {
inventory.add(obj);
obj.moveTo(obj.priority)
obj.selectable = false;
inventory.renderAll();
console.log(inventory.getObjects().indexOf(obj), obj.priority)
}, {
id: resp.Items[x].Name,
creator: resp.Items[x].Creator.Username,
priority: resp.Items[x].Priority,
category: resp.Items[x].Type
});
}
I am trying to use moveTo method with no success at all. the console.log call shows always 0, 1, 2, 3... instead of the moveTo index
I get no errors and item.priority exists so... I am missing something I guess
moveTo() is only rearranging objects in an array. You shouldn't think of them as layers that can have any Id as much as objects in an array. So you can't move something to an index of 10 unless there are 11 objects.
A better option might be to load all objects first and sort them based on priority and then add them to the canvas based on that order.

Gideros game engine box2d bodies

I am going to make a simple Game. my code have many bodies in on timer function (every second for example):
local function onTimer()
local sx = 20
local sy = 20
body = world:createBody{type = b2.DYNAMIC_BODY, position = {x = i*48, y = 50}}
local shape = b2.PolygonShape.new()
-- box images are 70x70 pixels. we create bodies 1 pixel smaller than that.
shape:setAsBox(20, 20)
body:createFixture{shape = shape, density = 1, restitution = 0.1, friction = 0.3}
rand = math.random(1,32)
sprite = createBoxSprite(0.6,0.6,rand)
stage:addChild(sprite)
actors[body] = sprite
actors_r[sprite] = body
table.insert(sp, sprite)
--print (sprite)
--print (sp[#sp])
sprite:addEventListener(Event.TOUCHES_BEGIN, onTouchBegin,sprite)
sprite:addEventListener(Event.TOUCHES_END, onTouchEnd,sprite)
i=i+1
all=all+1
--print(all)
if i>8 then
i=1
end
if all>88 then
print("game over")
end
end
I want remove any body on click. but with this listeners when clicked all of sprites removed only.
function onTouchBegin(e)
e:removeFromParent()
end
function onTouchEnd(e)
end
how to do this?
It actually works like this:
-- receive sprite as first parameter and event as second
function onTouchBegin(sprite, e)
-- check if event hit this exact sprite
if sprite:hitTestPoint(e.touch.x, e.touch.y) then
-- remove it from the stage
sprite:removeFromParent()
-- also lets not forget about references in actors tables
local body = actors_r[sprite]
actors[body] = nil
actors_r[sprite] = nil
-- and we could either destroy the body here
world:destroyBody(body)
-- or reuse it to attach to the next sprite
end
end

Using Corona how can I get my app to register multiple button presses when the user performs a single drag gesture?

I am generating a 6x6 grid of buttons using widget.newButton. I would like the user to be able to add numbers to a selection by touching the screen and then dragging their finger over the desired buttons. For example if I wanted to select "811030" (i.e the top row of the grid) then I would just drag my finger over it.
Here is the code I have so far:
local widget = require( "widget" )
local function handleButtonEvent( event )
local phase = event.phase
if "moved" == phase then
print("Button Pressed")
end
end
function tileRow(numTiles, padding)
local tileWidth = (display.contentWidth / numTiles) - padding
local x = padding/2
local y = display.contentHeight - numTiles * (tileWidth + padding)
for i = 1, numTiles, 1 do
for j = 1, numTiles, 1 do
local myButton = widget.newButton
{
left = x,
top = y,
width = tileWidth,
height = tileWidth,
id = "button_"..i..j,
label = math.random(0,9),
onEvent = handleButtonEvent,
}
x = x + tileWidth + padding
end
x = padding/2
y = y + tileWidth + padding
end
end
tileRow(6,1)
Just access the label inside the event handler, and build your full number from there.
I'll let you handle the corner cases, like putting fullNumber back to "" at one point :)
local fullNumber = ""
local function handleButtonEvent( event )
local phase = event.phase
local btn = event.target
local btnLabel = btn.label
if "moved" == phase then
print("Button Pressed with label:"..btnLabel)
fullNumber=fullNumber..btnLabel
print("Full number: "..fullNumber)
end
end
Cheers !
Get the button under the finger
In handleButtonEvent, you can retrieve the coordinates (x, y) where the user is touching and moving his finger. Indeed the event.target is not enough to your purpose because the event.target will always be equal to the first touched button.
You have to implement this function GetMyButton(x, y) that will return a widget.newButton. It should not be hard.
Get the label of the found button
According to widget_button.lua, to get the label of a button you should do :
local btnLabel = btn:getLabel()
Concatenate the found labels (be aware of duplication)

How to animate random objects created on screen in corona sdk

I am trying to animate random objects that are created individually on the screen at random positions,
objects will be created at a random location and move towards the right and as they crosses the screen width then they will spawn from the left (beyond the screen). I am not able to understand how to animate randomly created objects on the screen. Below are the codes which i used. Please help. thanks....
--objects that are created randomly
local randoms=math.random
local randomx,randomy
local randomobjname1,randomobjname2
for i=1, 2 do
randomx=randoms(200,400)
randomy=randoms(600,800)
local xlocation=randomx
local ylocation=randomy
local RandomObject[i]=display.newImage("object.png")
RandomObject[i].x=xlocation
RandomObject[i].y=ylocation
if i==1 then
randomobjname1=RandomObject[i]
elseif i==2 then
randomobjname2=RandomObject[i]
end
local function animateobj()
--in this line i have confusion how to pass random x position that i got previously from the above function
randomobjname1.x=randomx
randomobjname2.x=randomx
transition.to(randomobjname1,{time=1500,x=700, onComplete=animateobj})
transition.to(randomobjname2,{time=1500,x=700, onComplete=animateobj})
end
end
Are you looking for this:
local RandomObject = {}
local xPos = {}
local transitionTime = 1500
local listener2 = function( obj )
transitionTime = 2000 -- U can select as ur need
RandomObject[obj.tag].x = xPos[obj.tag]-400 -- U can even choose a difft. val than '400'
animateobj(obj.tag)
end
function animateobj(i_)
transition.to(RandomObject[i_],{time=transitionTime,x=400+xPos[i_], onComplete=listener2})
end
for i=1, 2 do
RandomObject[i]=display.newImage("object.png")
RandomObject[i].x = math.random(100,300)
RandomObject[i].y = math.random(100,400)
RandomObject[i].tag = i
xPos[i] = RandomObject[i].x
animateobj(i)
end
Keep Coding............ :)

Resources