Jump to content

Navigating through multiple pages


randomrat

Recommended Posts

Hi All,

I'm an embedded newbie here who has stumbled across uGFX in my research to create a nice GUI for a personal project/interest. I have some basic knowledge on C and want to try something different. I have been getting to grips with using the uGFX libraries and uGFX studio, which was a little difficult to start with, but the more I am beginning to understand it the more impressed I get with how powerful it is!

Anyway, back to my post...I have a couple of problems but I was not sure whether I should split them into multiple posts. Please advise me to do so if necessary.

My project currently requires 6 different "pages" which are accessible from buttons on other pages. With the aid of uGFX studio, I created multiple "display pages" and some placeholder buttons that will be used to jump between the pages (these will be custom image buttons).

static void createPageMain(void)
{
	GWidgetInit wi;
	gwinWidgetClearInit(&wi);

	// create container widget: ghContainerPageMain
	wi.g.show = FALSE;
	wi.g.x = ;
	wi.g.y = ;
	wi.g.width = 480;
	wi.g.height = 272;
	wi.g.parent = ;
	wi.text = "Container";
	wi.customDraw = ;
	wi.customParam = ;
	wi.customStyle = ;
	ghContainerPageMain = gwinContainerCreate(, &wi, );

	// create button widget: ghBtnSystem
	wi.g.show = TRUE;
	wi.g.x = 30;
	wi.g.y = 50;
	wi.g.width = 120;
	wi.g.height = 20;
	wi.g.parent = ghContainerPageMain;
	wi.text = "System";
	wi.customDraw = gwinButtonDraw_Normal;
	wi.customParam = ;
	wi.customStyle = ;
	ghBtnSystem = gwinButtonCreate(, &wi);

	// Create label widget: ghLblMain
	wi.g.show = TRUE;
	wi.g.x = 200;
	wi.g.y = ;
	wi.g.width = 120;
	wi.g.height = 20;
	wi.g.parent = ghContainerPageMain;
	wi.text = "Main Screen";
	wi.customDraw = gwinLabelDrawJustifiedCenter;
	wi.customParam = ;
	wi.customStyle = ;
	ghLblMain = gwinLabelCreate(, &wi);
	gwinLabelSetBorder(ghLblMain, FALSE);

	// create button widget: ghBtnCombFilter
	wi.g.show = TRUE;
	wi.g.x = 190;
	wi.g.y = 50;
	wi.g.width = 120;
	wi.g.height = 20;
	wi.g.parent = ghContainerPageMain;
	wi.text = "Comb Filter";
	wi.customDraw = gwinButtonDraw_Normal;
	wi.customParam = ;
	wi.customStyle = ;
	ghBtnCombFilter = gwinButtonCreate(, &wi);

	// create button widget: ghBtnPreFilter
	wi.g.show = TRUE;
	wi.g.x = 340;
	wi.g.y = 50;
	wi.g.width = 120;
	wi.g.height = 20;
	wi.g.parent = ghContainerPageMain;
	wi.text = "Pre Filter";
	wi.customDraw = gwinButtonDraw_Normal;
	wi.customParam = ;
	wi.customStyle = ;
	ghBtnPreFilter = gwinButtonCreate(, &wi);
	
	
//	wi.g.show = TRUE;
//	wi.g.x = 160;
//	wi.g.y = 10;
//	wi.g.width = 120;
//	wi.g.height = 120;	
//	ghImage2 = gwinImageCreate(NULL, &wi.g);
//	gwinImageOpenMemory(ghImage2, PumpGrey);

}


static void createPageSystem(void)
	etc

static void createPageCombFilter(void)
	etc

uGFX Studio automatically generated a guiEventLoop function where the GEvents are captured. 

void guiEventLoop(void)
{
	GEvent* pe;

	while (1) {
		pe = geventEventWait(&gl, 0);
		switch (pe->type) {
			case GEVENT_GWIN_BUTTON:
				if (((GEventGWinButton*)pe)->gwin == ghBtnSystem) {
					guiShowPage(1);
				}
				
				else if (((GEventGWinButton*)pe)->gwin == ghBtnCombFilter) {
					guiShowPage(2);
				}
				
				else if (((GEventGWinButton*)pe)->gwin == ghBtnPreFilter) {
					guiShowPage(3);
				}
				
				else if (((GEventGWinButton*)pe)->gwin == ghBtnBack) {
					guiShowPage(0);
				}
				
				else if (((GEventGWinButton*)pe)->gwin == ghBtnBack1) {
					guiShowPage(0);
				}
				
				break;
				
			default:
				break;
		}

	}
}

 

That works fine, however I want every page, APART from the homepage (page 0) to have a "back" button, navigating to the previous page.

As you can see in the code above, I have had to create a separate button for each page which directs it to the page before (giving the appearance of back)  It seems like I cannot create just one button that can be dynamically reused depending on the page that is being displayed. 

A very crude way of knowing what page I'm on can be handled like this, but it doesn't solve the problem of only having one button.

static const uint32_t currentpage = ;

...
...

guiShowPage(1);
currentpage = 1;
...
...

else if (((GEventGWinButton*)pe)->gwin == btnBack) {	
	backPage()
}

...
...

void backPage(void)
{

	if (currentpage == 1)
		guiShowPage(); //guishowpage containes currentpage = 0;
	
	else if (currentpage == 2)
		guiShowPage();
	
	else if (currentpage == 3)
		guiShowPage();

	else{}
	
}

I worry that I will end up with a sea confusing code and buttons that effectively do the same thing.

Is it best to create all the pages at runtime and then show them necessary. Would it be better to only create them as and when needed and destroy (gwinDestroy()) them once I navigate to another page?

I appreciate your time in reading this.

I was going to ask for help about making by buttons into images as I appear to be struggling but I think I should leave that for now and solve this problem first?

Link to comment
Share on other sites

Hello and welcome to the community!

We are happy to hear that you managed to get µGFX working, well done!
If you have any feedback on what made it a bit difficult we are all ears! We are happy to improve our documentation to make it easier to get started. Sadly it's not as easy as everything depends heavily on the hardware, the operating system, the IDE that you are using and so on.

The µGFX-Studio is in a very early stage of development and sadly it lacks many many features which keep it from being a tool that can be used productively. The µGFX library itself provides tons of features that are currently simply not supported by the µGFX-Studio. Whenever you need to implement some more advanced behavior you have to fallback to modifying the code generated by the studio.

Regarding the button(s): One of the main goals of the µGFX library is to be as fast and as small as possible in order to be able to run on virtually any platform. However, this goal puts some limitations on certain features. One of those limitations is taht the GWIN module (the module that handles the widgets) doesn't allow to dynamically change the parent of a widget. As a display page is nothing else but a container that covers the entire display area the button you place on the display page becomes a child of that container (display page) and it cannot be used on a different display page. There are three ways to handle this while sticking to the µGFX philosophy:

  1. Create one dedicated button widget on each display page. Give them the the exact same parameters (position, dimensions, text, font, ...) so it appears to the user that it's the same button. Call guiShowPage() with a different index parameter from each button.
     
  2. Make the containers smaller so that there's an area on the display that's not covered by any container. In that area you can place your navigation buttons which will then be visible on ALL display pages because the display page container doesn't cover this navigation bar area. However, in your case where you don't want to show the navigation buttons on one of the display pages you'd have to manually hide those navigation buttons when the home widget is active.
     
  3. Use the tabset widget (http://wiki.ugfx.org/index.php/Tabset) for all non-home display pages. The home display page will be a dedicated display page (container) that covers the entire area that you make visible while hiding the tabset.

Note that you have full control over how a widget looks like. It's possible to overwrite the paint() function of any widget. That way you can change how the buttons looks like or how the tabset widget renders the tabs. You can find more information about that (and an example) here: http://wiki.ugfx.org/index.php/Creating_a_custom_rendering_routine
If you have more specific needs it's even possible to write an entire widget yourself. It's not as hard as it sounds and there's an example in the /demos directory of the uGFX library.

Regarding the display page creation: Creating a display page is a very time consuming operation and is non-deterministic if you're using dynamically allocated objects. Creating the display pages at startup and keeping them in memory and just changing the visibility is a lot faster than destroying and reconstructing them each time. Furthermore, depending on what you are doing (eg. when sampling some data that requires huge buffers) it's possible that you run out of memory during runtime which will make the creation of the display pages fail at which point your user won't be happy because you can't change the GUI page which will leads to the user not having the ability to (fully) control the device.
If you are concerned a lot about memory usage, dynamic memory allocation and so on: It's possible to use the µGFX library completely static. For example, all the gwinXxxCreate() functions take a pointer to the corresponding object as the first parameter. If that pointer is NULL the GWIN module will automatically create the object dynamically, otherwise it will use the one that you provided (which allows you to create a fully static GUI!).

Regarding the forum: Feel free to create a dedicated thread for each of your problems/questions. It's easier for us to maintain and people that use the forum search will not have to digg through a lot of (for them) unrelated stuff :)

Regarding your question with the button images: There are two possibilities: The button widget provides an image rendering routine which allows you to pass a pointer to an image to the rendering routine. That way the ENTIRE button will be an image. If you are looking for a solution where the button stays a button and there's just a small icon next to the text, look at the article linked above. The example for how to create a custom rendering routine shows exactly that :)

I hope that helps. Please don't hesitate to ask any further questions.

Link to comment
Share on other sites

Hello Joel,

Apologies in the delayed response.

I thought I'd give some closure on this thread and say I followed Option 1 and created dedicated buttons for every page. I have named them as best as possible to avoid confusion with other buttons that also do the same thing (but on another page). All works well and I can successfully switch between pages - That's one small piece of the puzzle solved!

Other things I have figured out following your documentation since my first post are: Adding multiple custom fonts, custom button images (although I need to try adding multiple images for one button), animated gifs (I get flickering, but the concept works) and ImageBox widgets! :) 

I'd love to write my experiences about uGFX someday, unfortunately the next university semester is about to start. It will have to wait for the summer, however in a nutshell I am so deeply impressed with all the work you and your team have done. Definitely inspiring and the thought gone into this project is self evident. My journey with uGFX will still continue. Keep it up! 

 

Many Thanks,

Raj

Edited by randomrat
Link to comment
Share on other sites

Thank you very much for your feedback and the positive words. We appreciate it a lot and we are very happy to hear that you like the µGFX library and we will continue to further improve it :)

Regarding multiple images: You can create a custom struct that contains multiple pointers to different images and pass that to your custom rendering routine via the custom parameter. Such a "configuration" or "control" structure allows you to pass as many parameters as you want to a custom renderer.

Please do not hesitate to ask when you have any other questions. We are happy to help where ever we can and we appreciate all kinds of feedback!

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...