Jump to content

Using GWIN with Multiple "Screens"


kengineer

Recommended Posts

Hello, I was wondering about the proper or intended use for the GWIN module when creating multiple screens. By screens, I mean separate screen layouts that may not be completely different. Is the intended use to create and destroy the widgets every time, or should I be reusing widgets across multiple screens? What is the most efficient way to use this?

Link to comment
Share on other sites

This is one of the questions that can't really be answered in a generic way: It depends a lot on the circumstances, the available resources, how often the widgets are used and so on. Never the less I'll try to explain the philosophy behind the current version of the GWIN module in order to make you aware of some of the issues/considerations:

The GWIN system can be used with fully static memory or fully dynamic memory. You might have noticed that you can pass a pointer to the corresponding widget object as the first parameter to each gwinXxxCreate() function. This allows to create a static object somewhere on the stack and the create call will simply initialize the required fields which is usually a very quick operation and never fails. If you pass a null-pointer, the GWIN system will automatically allocate the required object. Dynamic memory allocation is a very non-deterministic operation and can take up a lot of time. Therefore, if you need to switch the pages often and performance is a critical issue it's not recommended to destroy the widgets each time - that is if you have the required memory to spare.
If there are any real-time constrains then you definitely have to work with static objects and therefore you are not supposed to ever destroy the widgets.
Another issue to consider is that if you destroy a widget and you have to recreate it afterwards, you might not have enough memory to do so on an embedded system. Are you able to handle that case? If the user wants to open a settings dialog and you can't construct one this can definitely be an issue. In that case not destroying the widgets of the settings dialog provides the advantage that the required memory is already 'reserved'.
Regarding the use of the same widget on multiple display pages: Currently a display page is defined as a container that covers the entire display area. Each widget gets the display page container passed as the parent argument. This way changing display pages is simply a matter of controlling the visibility of just the display pages. However, the display page container controls the visibility of all its children. If you hide a container it will ripple through and hide all child widgets in that container. This raises the limitation that you can't put a widget on a display page and simply show it on other pages as well: You'll have to create one widget for each page.
In certain situations there's a work around: For example, if you need navigation buttons to change between display pages you can add the navigation control elements to the bare display and make all display pages smaller so that the display page container doesn't cover the entire area. Note that as per the previously noted definition of "a display page" this won't be a display page no more but just a regular container on the display. That's also the reason why the µGFX-Studio (currently?) doesn't support this feature.
In order to stay away from the workarounds you're supposed to have one individual widget object for each display page.

To summarize:

  • One individual widget object per display page
  • Only destroy the widgets if you have the memory to re-create them afterwards (or if you can handle the out-of-memory situation)
  • Only destroy the widgets if you can cope with the resulting performance drop if working with dynamic memory.

 

I guess that helps somehow...
Please don't hesitate to ask if you have any other (more specific?) questions. We're happy to help wherever we can.

Link to comment
Share on other sites

  • 2 weeks later...

So I'm most likely going to use the gwinShow and gwinHide functions (with widgets or containers) to show things properly based on the current screen I'm on.

I've set a custom style with a background color for some buttons, however I find that when I hide them, they are replaced with a white background where the button used to be. Is this normal behavior or am I doing something wrong?

Link to comment
Share on other sites

2 hours ago, kengineer said:

I've set a custom style with a background color for some buttons, however I find that when I hide them, they are replaced with a white background where the button used to be. Is this normal behavior or am I doing something wrong?

That is the expected behavior. When you hide the widget the window manager has to do something to get rid of them. It can't just "disable the pixels", it actually has to "overwrite" them with something. That something is the background color that is specified in the widget style that is applied to widget. Therefore, to get "transparency" effects you want to use the same backgrounds colors for all the related elements.

The other solution / workaround is to redraw the element that is below the widget after the hiding operation. That way the underlying widget will overwrite the newly drawn background color rectangle with whatever is supposed to be there.
Note that this is inefficient as some as the pixels that in the area of the widget that you are hiding get a new color twice: First the clearing with the background color and then the underlying widget that draws above them. Depending on your platform/setup/resources this isn't a big deal as even the cheapest embedded LCD controllers have rectangle-filling functions that make sure that the filling with the background color is very fast. However, if that is not the case you might want to consider rendering everything in a pixmap before you write it to the actual LCD (framebuffer). This is a classic trade-off between memory and CPU time so depending on what you have and what you need this might not be the best solution.

Link to comment
Share on other sites

13 minutes ago, Joel Bodenmann said:

That is the expected behavior. When you hide the widget the window manager has to do something to get rid of them. It can't just "disable the pixels", it actually has to "overwrite" them with something. That something is the background color that is specified in the widget style that is applied to widget.

The other solution / workaround is to redraw the element that is below the widget after the hiding operation. That way the underlying widget will overwrite the newly drawn background color rectangle with whatever is supposed to be there.

Hi Joel,

What I'm saying is that the widget is not getting "erased" with the background color that I specified for the widget, it's white instead (I specified a non white custom color for the background in the custom style used for the widget).

Link to comment
Share on other sites

Yes. The bacground color in the widget is its own background, not the background color of the underlying surface.

When a widget is hidden its parent is checked. If the parent exists and can draw itself that region is redrawn by redrawing the parent with a limited clip area.

If there is no parent or the parent can't redraw itself (eg graph), it uses some background color - i can't remember which one right now but i think the code is in gwin_wm.c although i am not positive about that.

Note ugfx doesn't understand overlapping windows so it is the strict parent/child relationship that determines underlying aurface redrawing. 

I hope that helps.

Link to comment
Share on other sites

This is the related code from /src/gwin/gwin_wm.c:

	void gwinSetVisible(GHandle gh, bool_t visible) {
		if (visible) {
			if (!(gh->flags & GWIN_FLG_VISIBLE)) {
				gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE|GWIN_FLG_BGREDRAW);
				_gwinUpdate(gh);
			}
		} else {
			if ((gh->flags & GWIN_FLG_VISIBLE)) {
				gh->flags &= ~(GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE);
				gh->flags |= GWIN_FLG_BGREDRAW;
				_gwinUpdate(gh);
			}
		}
	}
void _gwinUpdate(GHandle gh) {
	if ((gh->flags & GWIN_FLG_SYSVISIBLE)) {
		if (gh->vmt->Redraw) {
			getLock(gh);
			gh->vmt->Redraw(gh);
			exitLock(gh);
		} else if ((gh->flags & GWIN_FLG_BGREDRAW)) {
			getLock(gh);
			gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
			exitLock(gh);
			if (gh->vmt->AfterClear)
				gh->vmt->AfterClear(gh);
		}
	} else if ((gh->flags & GWIN_FLG_BGREDRAW)) {
		getLock(gh);
		gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor());
		exitLock(gh);
	}
	gh->flags &= ~(GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
}

Note that gwinShow() and gwinHide() are just convenience wrappers for gwinSetVisible():

#define gwinShow(gh) gwinSetVisible(gh, TRUE)
#define gwinHide(gh) gwinSetVisible(gh, FALSE)

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...