Multiline wrapping text in a newScrollView with a mask

Hi all!

I’m in need of a method to display dynamic text in a scrolling box that auto-wraps the text. I’ve tried various methods found by searching this site and what I’ve come up with is a combination of a newScrollView widget with a mask containing a display.newText box. However, for the life of me I cannot get the mask to work! The mask does not line up with my “width” and “height” with an origin point at “left”, “top”. I made sure that the mask and newScrollView dimensions are multiples of 4.

I clearly don’t understand how to create the mask and your help in this  would be greatly appreciated. 

local group = display.newGroup() local width = 252 local height = 168 local left = 100 local top = 200 local widget = require "widget" --------------------------------------- -- getMask --------------------------------------- -- Function from Corona post -- create mask -- width: width of visible area -- height: height of visible area -- dir: system directory or nil to use default system.TemporaryDirectory -- grp: display group to use instead of visible rectangle (removed from display during call) function getMask( width, height, dir, grp, forcenew ) print("getMask") print(width, height) local filename = "mask-"..width.."x"..height..".png" local path = system.pathForFile( filename, dir or system.TemporaryDirectory ) local fh, errStr = io.open( path, "r" ) if (forcenew or not fh) then local mwidth = width+8; mwidth=mwidth+(8-(mwidth%8)) local mheight = height+8; mheight=mheight+(8-(mheight%8)) print(mwidth, mheight) -- create the mask group and the surrounding black area local maskgroup = display.newGroup() local invisible = display.newRect(maskgroup,0,0,mwidth,mheight) local visible = grp -- create the visible rectangle or use the parameter group if (grp) then maskgroup:insert( grp ) visible = grp else visible = display.newRect(maskgroup,0,0,width,height) end invisible.x,invisible.y = 0,0 visible.x,visible.y = 0,0 invisible:setFillColor(0,0,0) maskgroup.x,maskgroup.y = display.contentCenterX, display.contentCenterY display.save( maskgroup, filename, dir or system.TemporaryDirectory ) maskgroup:removeSelf() print("created mask: "..filename) else io.close( fh ) print("loaded mask: "..filename) end return graphics.newMask( filename, dir or system.TemporaryDirectory ) end local descriptionScrollView = widget.newScrollView { left = left, top = top, width = width, height = height, hideBackground = true, horizontalScrollDisabled = false, verticalScrollDisabled = false, hideScrollBar = true, } group:insert(descriptionScrollView) local mask = getMask( width, height, nil, nil, true) descriptionScrollView:setMask(mask) descriptionScrollView.maskX = descriptionScrollView.contentWidth \* 0.5 descriptionScrollView.maskY = descriptionScrollView.contentHeight \* 0.5 descriptionScrollView.maskScaleX = display.contentScaleX descriptionScrollView.maskScaleY = display.contentScaleY local txt = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." local description = display.newText(txt, 0, 0, width, 0, native.systemFont, 14 ) description:setTextColor( 255 ) descriptionScrollView:insert(description)

Note, the getMask function is an awesome piece of code taken from a post elsewhere on this site that dynamically generates a mask file.

Thanks!

Oh, and I’m on build 1076.

Hi @alexfx,

At a quick glance, I think you need to apply the mask using the widget’s “maskFile” parameter, instead of trying to apply the mask post-creation. Please review the documentation here:

http://docs.coronalabs.com/api/library/widget/newScrollView.html

Hope this works for you,

Brent

I seem to have got it working ok now. But there is a new issue with diagonal lines when simulating an Android device across the text when I incorporate the “Ultimate config.lua” file from http://www.coronalabs.com/blog/2012/12/04/the-ultimate-config-lua-file. Is this file still “valid”? When the config isn’t present all seems well.

Diagonal lines is usually an indication that the mask file isn’t correct.  It’s height and width needs to be evenly divisible by 4 and there has to be enough black pixels around it.  I usually make sure I have at least 4 and that the final image size is also evenly divisible by 4.

Indeed, the mask that is created when there is no “ultimate config.lua file” works fine. But as soon as it’s in place it stops working. I suspect the scaling indicated in the file is causing this.

It looks like my code works fine on the Android device but the simulator (build 1076) shows the diagonal lines, so it looks like a simulator bug. Thanks!

Is the text slanted like an over-aggressive italics?

If so pick up the latest public build (1135).  I think that bug got fixed after 1076.  It’s a simulator only problem.

Oh, and I’m on build 1076.

Hi @alexfx,

At a quick glance, I think you need to apply the mask using the widget’s “maskFile” parameter, instead of trying to apply the mask post-creation. Please review the documentation here:

http://docs.coronalabs.com/api/library/widget/newScrollView.html

Hope this works for you,

Brent

I seem to have got it working ok now. But there is a new issue with diagonal lines when simulating an Android device across the text when I incorporate the “Ultimate config.lua” file from http://www.coronalabs.com/blog/2012/12/04/the-ultimate-config-lua-file. Is this file still “valid”? When the config isn’t present all seems well.

Diagonal lines is usually an indication that the mask file isn’t correct.  It’s height and width needs to be evenly divisible by 4 and there has to be enough black pixels around it.  I usually make sure I have at least 4 and that the final image size is also evenly divisible by 4.

Indeed, the mask that is created when there is no “ultimate config.lua file” works fine. But as soon as it’s in place it stops working. I suspect the scaling indicated in the file is causing this.

It looks like my code works fine on the Android device but the simulator (build 1076) shows the diagonal lines, so it looks like a simulator bug. Thanks!

Is the text slanted like an over-aggressive italics?

If so pick up the latest public build (1135).  I think that bug got fixed after 1076.  It’s a simulator only problem.

Brent, I reviewed the documentation again and can’t see any indication that scrollView will not support dynamic mask application post-creation using scrollView:setMask(mask). Can you kindly confirm if this is the case?

Dynamic mask creation and application is very important to be able to cope with the ever increasing Android display variation so it would be wonderful if this capability is supported. Thanks

Hi Kerem,

It may seem like this is possible, but I checked into it further and it probably wouldn’t work. The widget “unit” itself is sort of a compilation of several elements, so you’d have to access lower-level aspects of it (private variables) to target the group and apply a mask to it. You probably  can  do this with some extra effort, especially if you dig into the open-source code and figure out how to pinpoint that… but simply saying “myScrollView:setMask()” probably isn’t going to work, sorry.  :frowning:

 

Take care,

Brent

Hi Brent, 

Thanks for confirming this ‘shortcoming’. I am still hopeful the whole dynamic masking issue will be addressed in a neat manner in the near future… With the graphics 2.0 in the making I hope this key challenge is being considered. It will make life easier for many app developers. game or business app alike. 

Best regards,

Kerem

Hi alexfx,
I wrote a very similar function to the getMask function you have in your example but I’ve been having difficulties with this when running my app on different devices with different content scaling. In my case this seems to be because display.save() creates an image that is too big. ie on iphone 4 it’s 640px wide rather than 320px wide and the mask just appears to do nothing because it’s  bigger than the screen. 

This is what it says in the docs for display.save()

NOTE:  When dynamic content scaling is enabled, display.save() saves the image in the device’s native resolution. For instance, if this method is used to save a 100 x 200 pixel display object, it will be saved as a 100 x 200 image on iPhone3 but it will be a 200 x 400 image on an iPhone4 (which would have the same content dimensions but more actual pixels). This is assuming that the config.lua file specifies the content width/height as 320x480 respectively.

Do you have any suggestions for this?

Hi Julius, take a look at my solution. Uses a different approach : http://developer.coronalabs.com/code/runtime-bitmap-maskfile-creation

Server created maskfiles downloaded at runtime and saved in Documents directory. Hope this works for you. Cheers