Dyanmic Tableview Mask?

Hi all,

We’re aware that many people want “dynamic masks” for use with widgets and we’re discussing how to implement it cross-platform. Whatever the solution is, it will come in the core graphics update. Most likely, it will not be “dynamic masks” per se, but a method to restrict rendering to a rectangle that’s parallel to the screen (in other words, you won’t be able to rotate this to some odd angle). I can’t state all of the specifics at this point, but I want to give some sense of what’s reasonable and what can be expected.

Brent

@Brent - Such masks should allow for people that make apps that use device screen percentages for their layout and not just absolute values! I am currently involved with such an app and thus don’t have to worry so much about the many device screen sizes.

Thanks for a Staff input!

@anderoth

I have the same sort of issue with my masked images/groups. I sent a bug in yesterday of a simple case, and Tom explained most of it… I used a black background rect in my group, which got rid of some of the stray pixels, but I had white borders still too… I put together a test case today and sent it in that demonstrates the bug. Just as background info, my test case code was:

[lua]
– When using display.save with a masked group, a white border appears around the catpure

– Load the mask
local myMask = graphics.newMask(“160x240Mask.png”)

local myImage = display.newImageRect( “Bg02.png”, 640,960 )
myImage.x = 320
myImage.y = 480
    
local myObject1 = display.newRect( 10, 10, 100, 150 ) – Create a rectangle object
local myObject2 = display.newCircle( 10, 10, 50 )   – Create a circle object
local myBlackRect = display.newRect( 0, 0, 1000, 1000 ) – Create a rectangle object

myObject1:setFillColor(64,64,128,255)
myObject2:setFillColor(64,128,64,255)

local g = display.newGroup()

g:insert(myBlackRect)
g:insert(myImage)
g:insert(myObject1)
g:insert(myObject2)

g:setMask(myMask)
g:setReferencePoint( display.CenterReferencePoint )    
g.maskX = g.x
g.maskY = g.y     

g.maskX = 80
g.maskY = 120

– save the entire group as a new display object
    display.save(g, “test.png”, system.TemporaryDirectory)
    
– reload the just saved image    
    local combined = display.newImageRect( “test.png”, system.TemporaryDirectory, 160, 240 )

combined.x, combined.y = 220, 380
print(" new image w,h == ", combined.width, combined.height)

[\lua]

@anderoth

I sent in case 22962 for this bug last week, but nothing shows up in the bug database…

Not sure if it got canned or what… Anyone at CoronaLabs know what happened to 22962? I can resubmit today, write a new example, heck, I’ll even jump through a flaming hoop if that helps :slight_smile:

Just let me know, this bug makes it look like I am creating white picture frames around captured images :confused:

Hi @mpappas,

I just checked; this bug is still in the database and it’s being investigated. I recall some recent chatter on it too, so it’s being reviewed and hopefully there’s a resolution for it soon.

Thanks,

Brent

To get around this I made this utility mask.lua

[lua]

local M = {}

local GENERIC_MASK_FILE = “images/generic_mask.png”

local GENERIC_MASK_WIDTH = 400

local GENERIC_MASK_HEIGHT = 400

M.applyMask = function(params)

    if params.object == nil then

        return

    end

    if params.width == nil then

        params.width = params.object.width

    end

    if params.height == nil then

        params.height = params.object.height

    end

    local myMask = graphics.newMask(GENERIC_MASK_FILE)

    params.object:setMask(myMask)

    params.object.maskScaleX = params.width/GENERIC_MASK_WIDTH

    params.object.maskScaleY = params.height/GENERIC_MASK_HEIGHT

    --there may be a need in the future add logic to the positioning for different reference points

    params.object.maskX = params.width/2

    params.object.maskY = params.height/2

end

return M

[/lua]

In my case I used an image that was 408 x 408 pixels image, a 400 x 400 white square with a 4 pixel wide black border. having a large image and scaling down works better than a small image scaling up (since when scaling up a grey area is created and thus not a crisp mask)

An example of usage:

[lua]

    local Mask = require(“mask”)

    

    …

    local OPTIONS_LIST_HEIGHT = 300

    local OPTIONS_LIST_HEIGHT = 200

    

    …

    local tableView = Widget.newTableView{

        width = OPTIONS_LIST_WIDTH,

        height = OPTIONS_LIST_HEIGHT,

        …

    }

    Mask.applyMask({

        object = tableView,

        width = OPTIONS_LIST_WIDTH,

        height = OPTIONS_LIST_HEIGHT

    })

[/lua]

When applying to a table view passing in explicit sizes seems to works better since getting the size from the table view object isn’t always exactly what you set it to be.

What an amazing 1st post!!! Thank you very much for sharing your solution. 

To get around this I made this utility mask.lua

[lua]

local M = {}

local GENERIC_MASK_FILE = “images/generic_mask.png”

local GENERIC_MASK_WIDTH = 400

local GENERIC_MASK_HEIGHT = 400

M.applyMask = function(params)

    if params.object == nil then

        return

    end

    if params.width == nil then

        params.width = params.object.width

    end

    if params.height == nil then

        params.height = params.object.height

    end

    local myMask = graphics.newMask(GENERIC_MASK_FILE)

    params.object:setMask(myMask)

    params.object.maskScaleX = params.width/GENERIC_MASK_WIDTH

    params.object.maskScaleY = params.height/GENERIC_MASK_HEIGHT

    --there may be a need in the future add logic to the positioning for different reference points

    params.object.maskX = params.width/2

    params.object.maskY = params.height/2

end

return M

[/lua]

In my case I used an image that was 408 x 408 pixels image, a 400 x 400 white square with a 4 pixel wide black border. having a large image and scaling down works better than a small image scaling up (since when scaling up a grey area is created and thus not a crisp mask)

An example of usage:

[lua]

    local Mask = require(“mask”)

    

    …

    local OPTIONS_LIST_HEIGHT = 300

    local OPTIONS_LIST_HEIGHT = 200

    

    …

    local tableView = Widget.newTableView{

        width = OPTIONS_LIST_WIDTH,

        height = OPTIONS_LIST_HEIGHT,

        …

    }

    Mask.applyMask({

        object = tableView,

        width = OPTIONS_LIST_WIDTH,

        height = OPTIONS_LIST_HEIGHT

    })

[/lua]

When applying to a table view passing in explicit sizes seems to works better since getting the size from the table view object isn’t always exactly what you set it to be.

What an amazing 1st post!!! Thank you very much for sharing your solution. 

I finally got around to trying @dennis97’s method and it seems to work well! Wohoo!!! Any idea why this method does not work with scrollViews? I tried and couldn’t get it to mask properly. Not sure why. 

I finally got around to trying @dennis97’s method and it seems to work well! Wohoo!!! Any idea why this method does not work with scrollViews? I tried and couldn’t get it to mask properly. Not sure why. 

have voted for a fix/improvement too 

have voted for a fix/improvement too 

@dennis97

Thank you for sharing the code! 

@ksan

It works fine on scrollViews as well. 

@dennis97

Awesome work - made my day as I thought I was going to have to write that to get around the issue.

Really appreciate you sharing the code!

@dennis97

Thank you for sharing the code! 

@ksan

It works fine on scrollViews as well. 

Thanks. I manage to have this dynamic mask’ing for my scrollview. Just to add :

"GENERIC_MASK_WIDTH " is the width of the mask file (png picture)

I implemented it as a function with slight changes ; A param which states the ‘mask filename’. In my example, the mask is 360x570 in size. By havingg this param, i have the flexibility of putting in other mask files to suit the page style.

 

 function applyMask(params) local GENERIC\_MASK\_FILE = DEFAULT\_MASK\_FILE\_TABLE\_VIEW local generic\_mask\_width = 360 local generic\_mask\_height = 570 if params.object == nil then return end if params.width == nil then params.width = params.object.width end if params.height == nil then params.height = params.object.height end if params.mask == nil then params.mask = DEFAULT\_MASK\_FILE\_TABLE\_VIEW end local myMask = graphics.newMask(params.mask) params.object:setMask(myMask) params.object.maskScaleX = params.width/generic\_mask\_width params.object.maskScaleY = params.height/generic\_mask\_height --there may be a need in the future add logic to the positioning for different reference points params.object.maskX = params.width/2 params.object.maskY = params.height/2 end

Thank you dennis97!  Just what I needed

@dennis97 thanks! It saves my day.

I was originally using display.save() to generate the mask file but something went wrong. I thought dennis method was not working! It took me one hour to realize the size of the saved file varies depending on the device. If someone is doing the same, hope it helps a bit.

@dennis97

Awesome work - made my day as I thought I was going to have to write that to get around the issue.

Really appreciate you sharing the code!