Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extending the Label class #1814

Closed
raresn opened this issue Mar 28, 2022 · 4 comments
Closed

extending the Label class #1814

raresn opened this issue Mar 28, 2022 · 4 comments

Comments

@raresn
Copy link

raresn commented Mar 28, 2022

Hello,
We have extended the label class, but in order to get the text to actually update on the stage, we have to do some extra steps, that i think are time consuming.

this.textRenderer.text = Info.minutesToText(_minutesInt);

And then we need to call:
this.createTextRenderer(); this.refreshTextRendererData(); this.refreshEnabled(); this.refreshTextRendererStyles(); this.layoutChildren();
Without these last 5 lines, we can't be sure that the text actually changes on the stage.
Wondering if we can do it in a smarter way. Any help is appreciated.
Thank you.

The whole class looks like this:
`public class TimeTextLabel extends Label
{
private var _minutes:Number;
private var _minutesInt:int;

	public function TimeTextLabel()
	{
		super();
		minutes = 0;
		_minutesInt = 0;
		this.text = "00:00";
		this.backgroundSkin = new Quad(16, 16, 0xFFFFFF);
		this.styleName = AppTheme.TEXT_TIME_LABEL_STYLE;
	}
	override public function dispose():void
	{
		if(this.backgroundSkin) {
			this.backgroundSkin.dispose();
			this.backgroundSkin = null;
		}

		super.dispose();
	}
	
	public function get minutes():Number
	{
		return _minutes;
	}

	public function set minutes(value:Number):void
	{
		_minutes = value;
		if(_minutesInt != (value | 0)) {
			// trace("[TimeTextLabel] - update text", value);
			_minutesInt = value | 0;
			this.text = Info.minutesToText(_minutesInt);
			
			/* must have for texture generation */
			this.textRenderer.text = Info.minutesToText(_minutesInt);
			this.createTextRenderer();
			this.refreshTextRendererData();
			this.refreshEnabled();
			this.refreshTextRendererStyles();
			this.layoutChildren();
		}
	}`
@raresn
Copy link
Author

raresn commented Mar 28, 2022

We are using this code to generate a list of labels containg the hours of the day, that we then convert to a texture and use when needed.

@joshtynjala
Copy link
Member

joshtynjala commented Mar 28, 2022

You don't need to call all of those other methods after setting the text property. You can, in fact, be sure that the rendered text will change when the text setter is called. The text setter calls invalidate(), which will cause the Label to update itself before the next time that Starling renders.

public function set minutes(value:Number):void
{
	_minutes = value;
	if(_minutesInt != (value | 0)) {
		// trace("[TimeTextLabel] - update text", value);
		_minutesInt = value | 0;
		this.text = Info.minutesToText(_minutesInt);
	}
}

@Adrian-S
Copy link

Adrian-S commented Apr 7, 2022

The problem is a bit more complex.

We are trying to draw on a RenderTexture the same Object, that extends a Sprite, containing this extended Label, multiple times. This is done only once on first run and texture is saved to png.

So rather than creating multiple objects, we try to create one, and draw it in different positions and with different text, and we do this in a for loop. We were not able to validate it and force it to show. If we don’t add that extra code it will render a texture with 00:00 only. We need to force it to paint on each update.

Maybe there is a better way to fill the texture with numbers. Any sugestion is appriciated.

The other issue here is this error:

Uncaught Error // Error // Error: Error #3768 // Error: Error #3768
	at starling.textures::ConcreteTexture/dispose()
	at feathers.controls.text::TextBlockTextRenderer/dispose()
	at starling.display::DisplayObjectContainer/removeChildAt()
	at starling.display::DisplayObjectContainer/removeChild()
	at feathers.controls::Label/createTextRenderer()
	at ro.app.items::TimeTextLabel/set minutes()

One sollution would be to add a condition and stop calling createTextRenderer(), since it's only required for texture generation. Out of the errors I've read, they were not in the texture generation part. I think error is given when probably app is in background. This might not be the most elegant fix.

Since February we had about 1000 errors related to this. Same object class is used multiple times, during the normal usage of the app, but I don't have a statistic for that. So 1000 errors could be low, or coult be high, but it's certanly enough to demand a patch.

Maybe in the future we will skip this dynamic generation and have all textures stored on a server based on DPI and download after install. Right now it's like a procedural texture, and saves the app 1-2Mb. For 3x resolution, this code generates 4 textures of 2048x2048px. But this is also a perfect copy of what air will render for text, and this was the main goal when we created this monster.

@joshtynjala
Copy link
Member

After the text gets set, the Label will be invalid, and it will need to update. Normally, this would happen before Starling renders the next frame. However, you can force it to happen immediately, like this:

label.minutes = newMinutes;
label.validate();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants