Libwiigui/tutorial

From WiiBrew
Jump to: navigation, search

Contents

Foreward

LibwiiGui is written in C++ and uses classes. Classes are a collection of functions and variables related to a single thing. You work with classes by creating instances of them, called objects. When using these objects, their public functions and variables can be accessed by a dot (.) in some cases, and an arrow (->) in other cases. This will become more understandable later on in the tutorial, but for now, know that when the object is created with an asterisk (*) you will be using the arrow (->), and when the object is created without the asterisk you will use the dot (.).

This tutorial uses the same design as the demo included with libwiigui. Every menu is created inside a function. The GUI updating routine is created as a function, and is in a thread. When wanting to change to a new menu, you set the menu variable to a value that denotes the menu you wish to change to. Again, this will become more apparent later on.

Lastly, before attempting to read this tutorial (or try to use libwiigui for that matter) you should already have at least a basic understanding of C++, if not more. You can easily find some online tutorials (cprogramming.com, cplusplus.com) or a book from your local library.

Setting Up

You first must have devkitPPC. devkitPPC is what allows programmer's to compile their programs for other systems, such as the Wii, PSP, and DS. This should be pretty straight-forward for Windows users. Just download the latest Windows installer, and go through the installer. When asked what to install, you must install devkitPPC. That allows you to compile for the PowerPC architecture, which the Wii uses. You also will need libogc, which is the library that lets you program for the Wii. Linux and Mac users should follow the instructions at http://wiki.devkitpro.org/index.php/Getting_Started/devkitPPC


If you haven't already done so, download libwiigui. You can extract this anywhere, as this is where your source will be for your entire project.

Object Creation

There are two ways an object (an instance of a class) can be created. We will use both methods when working with LibwiiGui. When you want an object to be able to be accessed outside of the function where it was made, you will want to create it with an asterisk, which declares a pointer to your object. You will want to use this approach for your main GuiWindow, which should contain the background and every other window (these other windows will be your menus). You also will want to initially set it to NULL for safety's sake:

GuiWindow * mainWindow = NULL;

These declarations should be at the top of the file, underneath the includes. Then, when calling the object's functions, you will use ->:

mainWindow->Append(&someElement);

In the above code, we are adding an object called someElement to mainWindow, using mainWindow's Append function.

If you want an object that is only relevant to the function you are in (e.g. a menu), you will want to declare the instance inside the function:

int menu_function(){
     GuiWindow menuwindow;
     GuiImage menuimage;
}

Then use the dot (.) to operate on the object

int menu_function(){
     GuiWindow menuwindow;
     GuiImage menuimage;
     menuwindow.Append(&menuimage);
}

The GuiElement

Every LibwiiGui object you create (except for GuiSound, GuiTrigger, and GuiImageData) will inherit from the GuiElement class. This means that you can use any GuiElement function in any GuiElement you use, allowing you to move, get the width of, and get the state of images, buttons, keyboards, option browsers, etc. The GuiElement (from libwiigui/gui.h) class defines the following public functions which you can use with any GuiElement:

		//!Constructor
		GuiElement();
 
		//!Destructor
		~GuiElement();
 
		//!Set the element's parent
		//!\param e Pointer to parent element
		void SetParent(GuiElement * e);
 
		//!Gets the element's parent
		//!\return Pointer to parent element
		GuiElement * GetParent();
 
		//!Gets the current leftmost coordinate of the element
		//!Considers horizontal alignment, x offset, width, and parent element's GetLeft() / GetWidth() values
		//!\return left coordinate
		int GetLeft();
 
		//!Gets the current topmost coordinate of the element
		//!Considers vertical alignment, y offset, height, and parent element's GetTop() / GetHeight() values
		//!\return top coordinate
		int GetTop();
 
		//!Sets the minimum y offset of the element
		//!\param y Y offset
		void SetMinY(int y);
 
		//!Gets the minimum y offset of the element
		//!\return Minimum Y offset
		int GetMinY();
 
		//!Sets the maximum y offset of the element
		//!\param y Y offset
		void SetMaxY(int y);
 
		//!Gets the maximum y offset of the element
		//!\return Maximum Y offset
		int GetMaxY();
 
		//!Sets the minimum x offset of the element
		//!\param x X offset
		void SetMinX(int x);
 
		//!Gets the minimum x offset of the element
		//!\return Minimum X offset
		int GetMinX();
 
		//!Sets the maximum x offset of the element
		//!\param x X offset
		void SetMaxX(int x);
 
		//!Gets the maximum x offset of the element
		//!\return Maximum X offset
		int GetMaxX();
 
		//!Gets the current width of the element. Does not currently consider the scale
		//!\return width
		int GetWidth();
 
		//!Gets the height of the element. Does not currently consider the scale
		//!\return height
		int GetHeight();
 
		//!Sets the size (width/height) of the element
		//!\param w Width of element
		//!\param h Height of element
		void SetSize(int w, int h);
 
		//!Checks whether or not the element is visible
		//!\return true if visible, false otherwise
		bool IsVisible();
 
		//!Checks whether or not the element is selectable
 
		//!\return true if selectable, false otherwise
 
		bool IsSelectable();
 
		//!Checks whether or not the element is clickable
 
		//!\return true if clickable, false otherwise
 
		bool IsClickable();
 
		//!Checks whether or not the element is holdable
 
		//!\return true if holdable, false otherwise
 
		bool IsHoldable();
 
		//!Sets whether or not the element is selectable
 
		//!\param s Selectable
 
		void SetSelectable(bool s);
 
		//!Sets whether or not the element is clickable
 
		//!\param c Clickable
 
		void SetClickable(bool c);
 
		//!Sets whether or not the element is holdable
 
		//!\param c Holdable
 
		void SetHoldable(bool d);
 
		//!Gets the element's current state
 
		//!\return state
 
		int GetState();
 
		//!Gets the controller channel that last changed the element's state
 
		//!\return Channel number (0-3, -1 = no channel)
 
		int GetStateChan();
 
		//!Sets the element's alpha value
 
		//!\param a alpha value
 
		void SetAlpha(int a);
 
		//!Gets the element's alpha value
 
		//!Considers alpha, alphaDyn, and the parent element's GetAlpha() value
 
		//!\return alpha
 
		int GetAlpha();
 
		//!Sets the element's scale
 
		//!\param s scale (1 is 100%)
 
		void SetScale(float s);
 
		//!Gets the element's current scale
 
		//!Considers scale, scaleDyn, and the parent element's GetScale() value
 
		float GetScale();
 
		//!Set a new GuiTrigger for the element
 
		//!\param t Pointer to GuiTrigger
 
		void SetTrigger(GuiTrigger * t);
 
		//!\overload
 
		//!\param i Index of trigger array to set
 
		//!\param t Pointer to GuiTrigger
 
		void SetTrigger(u8 i, GuiTrigger * t);
 
		//!Checks whether rumble was requested by the element
 
		//!\return true is rumble was requested, false otherwise
 
		bool Rumble();
 
		//!Sets whether or not the element is requesting a rumble event
 
		//!\param r true if requesting rumble, false if not
 
		void SetRumble(bool r);
 
		//!Set an effect for the element
 
		//!\param e Effect to enable
 
		//!\param a Amount of the effect (usage varies on effect)
 
		//!\param t Target amount of the effect (usage varies on effect)
 
		void SetEffect(int e, int a, int t=0);
 
		//!Sets an effect to be enabled on wiimote cursor over
 
		//!\param e Effect to enable
 
		//!\param a Amount of the effect (usage varies on effect)
 
		//!\param t Target amount of the effect (usage varies on effect)
 
		void SetEffectOnOver(int e, int a, int t=0);
 
		//!Shortcut to SetEffectOnOver(EFFECT_SCALE, 4, 110)
 
		void SetEffectGrow();
 
		//!Gets the current element effects
 
		//!\return element effects
 
		int GetEffect();
 
		//!Checks whether the specified coordinates are within the element's boundaries
 
		//!\param x X coordinate
 
		//!\param y Y coordinate
 
		//!\return true if contained within, false otherwise
 
		bool IsInside(int x, int y);
 
		//!Sets the element's position
 
		//!\param x X coordinate
 
		//!\param y Y coordinate
 
		void SetPosition(int x, int y);
 
		//!Updates the element's effects (dynamic values)
 
		//!Called by Draw(), used for animation purposes
 
		void UpdateEffects();
 
		//!Sets a function to called after after Update()
 
		//!Callback function can be used to response to changes in the state of the element, and/or update the element's attributes
 
		void SetUpdateCallback(UpdateCallback u);
 
		//!Checks whether the element is in focus
 
		//!\return true if element is in focus, false otherwise
 
		int IsFocused();
 
		//!Sets the element's visibility
 
		//!\param v Visibility (true = visible)
 
		virtual void SetVisible(bool v);
 
		//!Sets the element's focus
 
		//!\param f Focus (true = in focus)
 
		virtual void SetFocus(int f);
 
		//!Sets the element's state
 
		//!\param s State (STATE_DEFAULT, STATE_SELECTED, STATE_CLICKED, STATE_DISABLED)
 
		//!\param c Controller channel (0-3, -1 = none)
 
		virtual void SetState(int s, int c = -1);
 
		//!Resets the element's state to STATE_DEFAULT
 
		virtual void ResetState();
 
		//!Gets whether or not the element is in STATE_SELECTED
 
		//!\return true if selected, false otherwise
 
		virtual int GetSelected();
 
		//!Sets the element's alignment respective to its parent element
 
		//!\param hor Horizontal alignment (ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTRE)
 
		//!\param vert Vertical alignment (ALIGN_TOP, ALIGN_BOTTOM, ALIGN_MIDDLE)
 
		virtual void SetAlignment(int hor, int vert);
 
		//!Called constantly to allow the element to respond to the current input data
 
		//!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD
 
		virtual void Update(GuiTrigger * t);
 
		//!Called constantly to redraw the element
 
		virtual void Draw();

Most functions are pretty self-explanatory. Some you will not use often, while others you will be using all the time (such as SetPosition). Remember, you will want to use these functions with the upper-most class you can. For example, if you set GuiImageData to a GuiImage, and then set the GuiImage to a GuiButton, you will want to set the position of the GuiButton, not the GuiImage.


Your First Image

Images are created using the GuiImage class. Images can either be loaded from the sd card, or from a buffer. There are quite a few things you will have to do, though, before you can display your image. Open demo.cpp from the libwiigui template.

First, we must initialize the video hardware, by using the function from video.cpp. This must be done in any wii application you make, even if you are not going to be displaying any images:

InitVideo();

If you are going to want sound, initilaize the sound hardware also:

InitAudio();

If you are going to be loading images from the sd card (or using the sd card for any other reason), you will need to initialize it:

fatInitDefault();

Next, you will need to start the Gui updating thread:

InitGUIThreads();

This is what writes any changes you made to the screen. Last, you would call the function that starts your main menu. In the demo, it is:

MainMenu(MENU_SETTINGS);

but it can be whatever you named your menu function.

Now, open menu.cpp. Find the MainMenu function. For anything you do in libwiigui, you will want to use "menus" to display anything, except for adding things to the background of your entire GUI, which you will do in the MainMenu function. A menu is simply a function, which should return an int. At the top, declare int menu = MENU_NONE, so if this changes, it will stop your loop later on. At the end of your function, return menu, which will let MainMenu() know which menu to load next.

int menu_function(){
     int menu = MENU_NONE;
     //everything else
     return menu;
}

To load an image, you declare an instance of the GuiImage class. Unless you are in the MainMenu function, you will want to declare it this way:

GuiImage image(&ImageData);

What is the ImageData inside the initializer function? Well before actually creating the image, you must load your image. This can be done by creating an instance of the GuiImageData class:

GuiImageData imagedata(image_source);

The image source is your image buffer, where the contents of the image are kept. The image must be in the png format, and have dimensions that are a multiple of 4. To load an image from an sd card to an image buffer, do the following (this is a little more complicated, and is slower anyway, so only use it if necessary) Somebody verify this please:

const u8 *image_name_png; //define the variables to hold your image file
const u32 image_name_png_size;
size_t amount_read;
FILE *fp = fopen("Path to image on sd card","r"); //open the png file
if(!fp) return; //make sure the file exists
 
fseek (fp , 0 , SEEK_END);
image_name_png_size = ftell(fp); //find the file size
rewind(fp);
 
image_name_png = new u8 [image_name_png_size]; //allocate memory for your image buffer
if(!image_name_png) return; //make sure memory allocated
 
amount_read = fread(image_name_png,1,image_name_png_size,fp); //read file to buffer
if(amount_read != image_size_png_size) return; //make sure it read everything
 
fclose(fp); //close file

You may be wondering how an image gets loaded into a buffer without the sd card. Whenever you want to add a new image, you must copy the image to the source/images folder, and add it to filelist.h:

extern const u8		image_name_png[];
 
extern const u32	image_name_png_size;

Then your image will be put into the image_name_png buffer when it is compiled. Just place your image in the images folder, and the compiler will take care of the rest for you.

Then, you must append your new image to the GuiWindow you are dealing with. Before doing do, you need to suspend the gui thread, so that you are not making changes to variables while the thread is reading them, and resume the thread after appending:

HaltGui();
mainWindow->Append(&image);
ResumeGui();

Unless the image is created as a pointer, you must have the & before it to pass the address of your GuiImage to the Append function.

Now, unless you want your menu to display for only a frame or two, you are going to want to keep the menu going somehow. Do this by adding a loop in it, usually a while loop that checks to see if your menu variable has changed:

while(menu == MENU_NONE){
    VIDEO_WaitVSync();
    //Other code (you will use this mostly with GuiButtons)
}

Last, you must remove any GuiElements you have Append()ed in your menu (unless it was declared globally, but you should still remove it) before returning to the MainMenu function, or else the GUI will keep trying to display an image that doesn't exist any more. Use the Remove() function, which takes in a GuiElement:

mainWindow->Remove(&image);

So that's all it takes to load an image. Easy, right? Here's an example of the complete proccess:

main.cpp:

#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <ogcsys.h>
#include <unistd.h>
#include "FreeTypeGX.h"
#include "video.h"
#include "audio.h"
#include "menu.h"
#include "input.h"
#include "filelist.h"
#include "demo.h"
 
int ExitRequested = 0;
 
void initall(){
	InitVideo(); // Initialise video
        InitAudio();
	InitGUIThreads();
	fatInitDefault();
}
 
void ExitApp()
{
	ShutoffRumble();
	StopGX();
	exit(0);
}
 
//---------------------------------------------------------------------------------
 
int main(int argc, char **argv) {
	initall();
	MainMenu(MAIN_SCREEN);
}

menu.cpp:

#include <gccore.h>
#include <ogcsys.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <wiiuse/wpad.h>
 
#include "libwiigui/gui.h"
#include "menu.h"
#include "demo.h"
#include "input.h"
#include "filelist.h"
 
static GuiImageData * pointer[4];
static GuiImage * bgImg = NULL;
static GuiSound * bgMusic = NULL;
static GuiWindow * mainWindow = NULL;
static lwp_t guithread = LWP_THREAD_NULL;
static bool guiHalt = true;
 
 
 
static void
ResumeGui()
{
	guiHalt = false;
	LWP_ResumeThread (guithread);
}
 
 
 
 
static void
HaltGui()
{
	guiHalt = true;
 
	// wait for thread to finish
	while(!LWP_ThreadIsSuspended(guithread))
		usleep(50);
}
 
 
 
static void *
UpdateGUI (void *arg)
{
	while(1)
	{
		if(guiHalt)
		{
			LWP_SuspendThread(guithread);
		}
		else
		{
			mainWindow->Draw();
 
			#ifdef HW_RVL
			for(int i=3; i >= 0; i--) // so that player 1's cursor appears on top!
			{
				if(userInput[i].wpad.ir.valid)
					Menu_DrawImg(userInput[i].wpad.ir.x-48, userInput[i].wpad.ir.y-48,
						96, 96, pointer[i]->GetImage(), userInput[i].wpad.ir.angle, 1, 1, 255);
				DoRumble(i);
			}
			#endif
 
			Menu_Render();
 
			for(int i=0; i < 4; i++)
				mainWindow->Update(&userInput[i]);
 
			if(ExitRequested)
			{
				for(int a = 0; a < 255; a += 15)
				{
					mainWindow->Draw();
					Menu_DrawRectangle(0,0,screenwidth,screenheight,(GXColor){0, 0, 0, a},1);
					Menu_Render();
 
				}
				ExitApp();
			}
		}
	}
	return NULL;
}
 
 
 
 
void
InitGUIThreads()
{
	LWP_CreateThread (&guithread, UpdateGUI, NULL, NULL, 0, 70);
}
 
 
 
 
 
int MenuDefault(){
 
     int menu=MENU_DEFAULT;
     GuiImageData image_data(image_png);
     GuiImage image(&image_data);
     HaltGui();
     mainWindow->Append(&image);
     ResumeGui();
     while(menu==MENU_DEFAULT){
          VIDEO_WaitVSync();
     }
 
     mainWindow->Remove(&image);
     return menu;
}
 
MainMenu(){
void MainMenu(int menu)
{
	int currentMenu = menu;
 
	#ifdef HW_RVL
	pointer[0] = new GuiImageData(player1_point_png);
	pointer[1] = new GuiImageData(player2_point_png);
	pointer[2] = new GuiImageData(player3_point_png);
	pointer[3] = new GuiImageData(player4_point_png);
	#endif
 
	mainWindow = new GuiWindow(screenwidth, screenheight);
 
	bgImg = new GuiImage(screenwidth, screenheight, (GXColor){50, 50, 50, 255});
	bgImg->ColorStripe(30);
	mainWindow->Append(bgImg);
 
	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
 
	ResumeGui();
 
	bgMusic = new GuiSound(bg_music_ogg, bg_music_ogg_size, SOUND_OGG);
	bgMusic->SetVolume(50);
	bgMusic->Play(); // startup music
 
	while(currentMenu != MENU_EXIT)
	{
		switch (currentMenu)
		{
			case MENU_DEFAULT:
				currentMenu = MenuDefault();
				break;
			default: // unrecognized menu
				currentMenu = MenuDefault();
				break;
		}
	}
 
	ResumeGui();
	ExitRequested = 1;
	while(1) usleep(50);
 
	HaltGui();
 
	bgMusic->Stop();
	delete bgMusic;
	delete bgImg;
	delete mainWindow;
 
	delete pointer[0];
	delete pointer[1];
	delete pointer[2];
	delete pointer[3];
 
	mainWindow = NULL;
}
}

If you want any other menu names (MENU_DEFAULT), you can define them in menu.h:

menu.h

#ifndef _MENU_H_
#define _MENU_H_
 
#include <ogcsys.h>
 
void InitGUIThreads();
void MainMenu (int menuitem);
 
enum
{
	MENU_EXIT = -1,
	MENU_NONE,
	MENU_SETTINGS,
	MENU_SETTINGS_FILE,
        MENU_DEFAULT
};
 
#endif

Buttons

Buttons are very useful, as they allow an image (or any other GuiElement) to be "clicked." GuiButtons add the following functions to your initial GuiElement functions:

		//!Constructor
 
		//!\param w Width
 
		//!\param h Height
 
		GuiButton(int w, int h);
 
		//!Destructor
 
		~GuiButton();
 
		//!Sets the button's image
 
		//!\param i Pointer to GuiImage object
 
		void SetImage(GuiImage* i);
 
		//!Sets the button's image on over
 
		//!\param i Pointer to GuiImage object
 
		void SetImageOver(GuiImage* i);
 
		//!Sets the button's image on hold
 
		//!\param i Pointer to GuiImage object
 
		void SetImageHold(GuiImage* i);
 
		//!Sets the button's image on click
 
		//!\param i Pointer to GuiImage object
 
		void SetImageClick(GuiImage* i);
 
		//!Sets the button's icon
 
		//!\param i Pointer to GuiImage object
 
		void SetIcon(GuiImage* i);
 
		//!Sets the button's icon on over
 
		//!\param i Pointer to GuiImage object
 
		void SetIconOver(GuiImage* i);
 
		//!Sets the button's icon on hold
 
		//!\param i Pointer to GuiImage object
 
		void SetIconHold(GuiImage* i);
 
		//!Sets the button's icon on click
 
		//!\param i Pointer to GuiImage object
 
		void SetIconClick(GuiImage* i);
 
		//!Sets the button's label
 
		//!\param t Pointer to GuiText object
 
		//!\param n Index of label to set (optional, default is 0)
 
		void SetLabel(GuiText* t, int n = 0);
 
		//!Sets the button's label on over (eg: different colored text)
 
		//!\param t Pointer to GuiText object
 
		//!\param n Index of label to set (optional, default is 0)
 
		void SetLabelOver(GuiText* t, int n = 0);
 
		//!Sets the button's label on hold
 
		//!\param t Pointer to GuiText object
 
		//!\param n Index of label to set (optional, default is 0)
 
		void SetLabelHold(GuiText* t, int n = 0);
 
		//!Sets the button's label on click
 
		//!\param t Pointer to GuiText object
 
		//!\param n Index of label to set (optional, default is 0)
 
		void SetLabelClick(GuiText* t, int n = 0);
 
		//!Sets the sound to play on over
 
		//!\param s Pointer to GuiSound object
 
		void SetSoundOver(GuiSound * s);
 
		//!Sets the sound to play on hold
 
		//!\param s Pointer to GuiSound object
 
		void SetSoundHold(GuiSound * s);
 
		//!Sets the sound to play on click
 
		//!\param s Pointer to GuiSound object
 
		void SetSoundClick(GuiSound * s);
 
		//!Constantly called to draw the GuiButton
 
		void Draw();
 
		//!Constantly called to allow the GuiButton to respond to updated input data
 
		//!\param t Pointer to a GuiTrigger, containing the current input data from PAD/WPAD
 
		void Update(GuiTrigger * t);

Once again, it's pretty self-explanatory. Buttons are simple to create, just remember, you must Append() the GuiButton to your GuiWindow, not the GuiImage. To create a button, declare an instance of the GuiButton class, giving the address your GuiImage (or another GuiElement) as the argument:

GuiImage image;
GuiButton button(&image);

Then you can use the button as if it were an image, except you can use SetTrigger, which sets when the button will be considered "clicked." To do this, you must first define a GuiTrigger. A GuiTrigger can be made by declaring an instance, the first argument being the Wiimote channel (use -1 for all), the second being the Wiimote buttons, and the third being the Gamecube buttons. For the buttons, you can do a bitwise-or ( | ) to "add" the buttons together, allowing the trigger to use more than one button.

GuiTrigger trigA;
trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);

Here I am setting a GuiTrigger to trigger when the wiimote button A, classic controller button A, or gamecube button A is clicked.

Then, you must set your button's trigger using SetTrigger, giving the address of your GuiTrigger as the only argument:

button.SetTrigger(&trigA);

Now, if your button is clicked, the GetState function will return STATE_CLICKED:

if(button.GetState() == STATE_CLICKED){
   //Do something because button was clicked
}


Program Flow

Now that you know a little more about buttons and images, you need to understand how a libwiigui project should be set up. One thing that is confusing for people trying to use libwiigui (or at least it was for me) is that there seem to be two different libraries. This is not true. The bare library is only what is in your libwiigui folder. Everything else (menu.cpp, video.h) is not part of the libwiigui library. They simply lay down the recommended way to effectively use the library. You will not need to worry much about any files except for menu.cpp, menu.h, and demo.cpp.

demo.cpp is your main cpp file, where your program starts in. If you want, you can rename this to main.cpp or something you see fitting. This file will just call a couple functions to initialize things, maybe set a few variables for you, and then calls your MainMenu() function, which takes care of everything else for you (unless you stop the gui for something else).

menu.h is what declares a couple of functions, and "enum's" the variables that will "describe" your menus (not exactly, but close enough for us). So both of those files are simple, just a few function calls, and a few declarations.

menu.cpp is what contains your entire gui. This is the only file (other than filebrowser.cpp) that actually uses libwiigui. All of this sort of "wraps" libwiigui into a usable form. menu.cpp will contain your UpdateGui() function. This is what Draw()s any changes you've made, draws the cursor(s) on the screen, and checks if you want to exit (so that it can fade out). UpdateGui() is used by creating a thread that runs UpdateGui(). Threads are what allow two different functions to execute simultaneously (not really, but it gives the illusion of it), so regardless of what you are doing elsewhere, your gui will still be displayed as long as the thread is running. However, threads can cause quite a few problems, one being when a variable is being written to and read from at the same time. To avoid this, you must call HaltGui() before Append()ing anything to the mainWindow. After your done Appending, call ResumeGui() to start the gui back up.

Everything that is displayed should be a part of a "menu" (with a few exceptions, such as snes9gx, which stops the gui when emulating, and starts it when you return to the main menu). A "menu" is not actually defined by libwiigui, rather it is the concept of having images, buttons, and any other GuiElement used grouped together to be displayed at once. These are typically going to be grouped into one GuiWindow that is appended to the mainWindow. A "menu" should follow the following basic outline:

static int stdmenu(){
	int menu = MENU_NONE;
 
                           ///All of the GuiElements here are optional, as you will be doing whatever pertains to your usage
	GuiText titleTxt("Menu Title", 28, (GXColor){255, 255, 255, 255});
	titleTxt.SetAlignment(ALIGN_LEFT, ALIGN_TOP);
	titleTxt.SetPosition(50,50);
 
	GuiSound btnSoundOver(button_over_pcm, button_over_pcm_size, SOUND_PCM);
	GuiImageData btnOutline(button_png);
	GuiImageData btnOutlineOver(button_over_png);
 
	GuiTrigger trigA;
	trigA.SetSimpleTrigger(-1, WPAD_BUTTON_A | WPAD_CLASSIC_BUTTON_A, PAD_BUTTON_A);
 
	GuiText backBtnTxt("Go Back", 22, (GXColor){0, 0, 0, 255});
	GuiImage backBtnImg(&btnOutline);
	GuiImage backBtnImgOver(&btnOutlineOver);
	GuiButton backBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
	backBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
	backBtn.SetPosition(100, -35);
	backBtn.SetLabel(&backBtnTxt);
	backBtn.SetImage(&backBtnImg);
	backBtn.SetImageOver(&backBtnImgOver);
	backBtn.SetSoundOver(&btnSoundOver);
	backBtn.SetTrigger(&trigA);
	backBtn.SetEffectGrow();
 
 
	GuiText okayBtnTxt("Okay", 22, (GXColor){0, 0, 0, 255});
	GuiImage okayBtnImg(&btnOutline);
	GuiImage okayBtnImgOver(&btnOutlineOver);
	GuiButton okayBtn(btnOutline.GetWidth(), btnOutline.GetHeight());
	okayBtn.SetAlignment(ALIGN_LEFT, ALIGN_BOTTOM);
	okayBtn.SetPosition(300, -35);
	okayBtn.SetLabel(&okayBtnTxt);
	okayBtn.SetImage(&okayBtnImg);
	okayBtn.SetImageOver(&okayBtnImgOver);
	okayBtn.SetSoundOver(&btnSoundOver);
	okayBtn.SetTrigger(&trigA);
	okayBtn.SetEffectGrow();
 
        ///Here is where you Halt the Gui, and append things. Notice that everything is appended to the GuiWindow w. w is then appended to the mainWindow.
 
	HaltGui();
	GuiWindow w(screenwidth, screenheight);
	w.Append(&backBtn);
	w.Append(&okayBtn);
	w.Append(&titleTxt);
	mainWindow->Append(&w);
	ResumeGui();
 
        ///This is the loop that keeps the menu running until told to stop
 
 
	while(menu == MENU_NONE) //The loop will run until menu is changed
	{
		VIDEO_WaitVSync (); //Waits for the vertical sync, to reduce flickering
 
		if(backBtn.GetState() == STATE_CLICKED) //Checks if you clicked back
		{
			menu = MENU_EXIT; //stops the loop, and returns MENU_EXIT, which will exit the app
		}
		if(okayBtn.GetState() == STATE_CLICKED) //Checks if you clicked okay
                {
			menu = MENU_MAIN; //stops the loop, and returns MENU_MAIN, which will start the main menu
		}
	}
	HaltGui(); //stop the gui
	mainWindow->Remove(&w); //remove your window to free memory
	return menu; //return the new menu to load
}
Personal tools
Resources
Community