Skip to content
jpastuszek edited this page Oct 21, 2010 · 2 revisions

DEVELOPMENT TUTORIALS
Let’s get started

1. Tutorials and project generator

The source code directory of nui contains a folder called tutorials. Have a look at the projects inside it, you will get a pretty good idea of the basic technics of nui.
Here we’re going to have a quick look to what you need to get started with nui, including a brief explanation of the tutorials.

Also, you can generate your own empty projects using the project generator of Yapuka. Yapuka is a nui application, located in nui source/tools/yapuka. It’s still work in progress but you can use it to generate an empty project already.

2. nuiApplication

The main object of your program inherits from nuiApplication:

class Application : public nuiApplication

It implements the entry and exit callbacks of any nui app:

void OnInit();
void OnExit (int Code);

In the cpp, a macro creates the application instance for you:

NGL_APP_CREATE(Application);

In ::OnInit, choose the 3D renderer and create the window:
Most of the tutorials will show you how to handle the window parameters.

// never forget that :)
nuiInit(NULL); 
nuiRenderer Renderer = eOpenGL;
nuiMainWindow::SetRenderer(Renderer);
[...]
mpMainWindow = new MainWindow(ContextInfo,Info, ShowFPS);

In ::OnExit, clean everything before the app exits:

// will properly delete the object tree attached to the window
delete mpMainWindow;
nuiUninit();

3. nuiMainWindow

class MainWindow : public nuiMainWindow

The main action is to implement two callbacks:

// called when the window has been asked to close
void MainWindow::OnClose()
{
 // don't close if a modal box is opened
 if (GetNGLWindow()->IsInModalState())  
  return;

 // properly quit the application. Will call the ::OnExit callback
  App->Quit(); 
}

// called when the window is properly created and connected to the nui system.
// You can start to build your GUI here.
void MainWindow::OnCreation()
{
 // create a vertical box for the GUI's layout, or any other container
  nuiVBox* pMainBox = new nuiVBox(0);

 // attach your main container to the window
 AddChild(pMainBox);
  
 // and continue to create the widget tree
  [...]
}

4. Create a simple GUI

Here is a simple example:

void MainWindow::OnCreation()
{
  // the main container: a vertical box with 2 cells
  nuiVBox* pMainBox = new nuiVBox(2);
  AddChild(pMainBox);

 // a title in the first cell
  nuiLabel* pTitle = new nuiLabel(_T("Hello World !"));
  pMainBox->SetCell(0, pTitle);
  
  // an horizontal box, with 2 cells, in the second cell
  nuiHBox* pBox = new nuiHBox(2);
  pMainBox->SetCell(1, pBox);
  
  // a button in the first cell
  nuiButton* pButton = new nuiButton(_T("go"));
  
  // 'nuiCenter' position means the button will take the minimum size at the center of the cell, 
  // try 'nuiFill' and other values to see the difference
  pButton->SetPosition(nuiCenter); 
  pBox->SetCell(0, pButton);
  
  // an image in the second cell: 'rsrc://' means the resources path from the app binary
  nuiImage* pImage = new nuiImage(_T("rsrc://decorations/image.png")); 

  // we choose to limit the size of the image. We could let the system handle that, 
  // the same way it does for the button.
  pImage->SetUserSize(100,100);
  pBox->SetCell(1, pImage);
}

5. nuiEvent: synchronous communication

5.1) Let’s make the button do something.

First, in you class header .h, declare an event sink to process the events and an event receiver for the button’s action:

class MainWindow: public nuiMainWindow
{
[...]
private:
  
  // event receiver
  bool OnButtonClick(const nuiEvent& rEvent);  

  // event sink
  nuiEventSink<MainWindow> mEventSink;
};

Next, initialize the event receiver in the class constructor:

MainWindow:MainWindow([...])
: nuiMainWindow([...]), mEventSink(this)

Then, connect the button action to the given receiver:

void MainWindow::OnCreation()
{
  [...]
  nuiButton* pButton = new nuiButton(_T("go"));
  [...] 
  mEventSink.Connect(pButton->Activated, &MainWindow::OnButtonClick, (void*)pLabel);
  [...]
}

bool MainWindow::OnButtonClick(const nuiEvent& rEvent)
{
  nuiLabel* pLabel = (nuiLabel*)rEvent.mpUser;

  pLabel->SetText(_T("Congrats for the best click ever..."));
  return true;
}

When the button is clicked, the event Activated is sent by the nuiButton instance, and is immediately caught by the ::OnButtonClick receiver.
The nuiEvent communication system is synchronous.

5.2) the optional user parameter

The nuiLabel pointer is given as a “user parameter” to the event subscription. It’s completely optional and it has no type: it is cast in void*.
Instead of using this “user parameter”, you could use an instance attribute. It’s a developer choice, depending on what your receiver has to do.
Also, if you need more flexibility and security about an event parameters, you should take a look to the nuiSignal class below.

5.3) receiver’s return value

true means the event is caught by the receiver instance => other subscribers won’t receive this event
false means the event is released => next subscriber will receive this event
Sometimes, like in the previous example, you don’t care about returning true or false: your button is the only subscriber to this event. But when there are several subscribers to the same event, and when the action has to be exclusively processed by a specific instance, this is something you should pay attention to.

5.4) events everywhere

Most of the existing widgets have their own events. It’s quite impossible to program a nui application without using them.
Most of the existing events are related to the user inputs (a button click, a choice from a combo box, a selection from a list, …), but they don’t necessarly deals with a GUI issue.

5.5) create your own events

In your own widgets (inheriting from a nui widget class), you can create any event you want for any purpose. It’s easy:

class MyWidget: public nuiButton
{
public:
  [...]
  nuiSimpleEventSource<0> MyEvent;

Let’s not worry about the templated shape of the event source right now, it’s not important.
Then, in the widget source code, you send the event when you want to warn the subscribers:

void MyWidget::MyMethod()
{
  SomeStuff();
  if (Condition())
    MyEvent();  // send the event
}