How to fix the Unbound module Graphics in an ocaml project

Image
From ~/pr/gitl/ocaml-gol In a constant effort to learn new programming languages, I'm currently trying to use ocaml , a free and open-source general-purpose, multi-paradigm programming language maintained at the Inria . It's basically an extension of Caml with object-oriented features. I'm mostly interested by its functionnal and pattern matching features but the module part of the language can be a bit difficult to understand for someone with little to none ML (Meta Language) background.   The error When trying to use the graphics module to create a graphical window and go just a little further than the simplest helloworld program, here is the result : If the project uses dune : (executable (name ocaml_project) (libraries lwt.unix graphics) ) with this code : let () = Printf.printf "Hello, world!\n";; Lwt_io.printf "Hello, world!\n";; Graphics.open_graph " 800x600";; The first times I built this project running the du...

How to make a modal dialog using Ogre/CEGUI

RainbruRPG is an open-source MMORPG project I'm working on since someday in early 2010's. I already posted multiple posts on this project (for example here and here). While its development is actually in pause for a while now, it is a great project to learn using new 3D/UI oriented libraries. CEGUI (short for Crazy Eddie's GUI System) is one of these libraries. It is a free MIT-licensed windowing and widgets library that run on top of Ogre3D but it can also run on other backends.


Rainbrurpg's modal dialog example
The RainbruRPG's not yet implemented modal dialog

The modal need

While CEGUI is a great library to create windows and complex screen, I need a standard dialog for NYI (Not Yet Implemented) features. For this, I'll try to create a modal dialog, i.e. a dialog with a blocking exec() function and a return value. It can have multiple buttons, each possibly with a different value but the blocking execution is needed :
ModalDialog md;
if (md.exec())
  {
     // handle positive event
  }

In the above example, the code is blocked in the exec() until the end user click on a button or close the dialog.

some issues still need to be fixed to make a modal dialog using CEGUI :
  1. We have to continue Ogre3D rendering during the blocking function;
  2. RainbruRPG currently uses many CEGUI GeometryBuffer objects and these are not drawn by Ogre3D;

The header

Here is the header sources but it is mainly based on another class (called CeguiDialog I will not include here. You can find it online at bitbucket. You may want to refer at least to its header because it contains some members and include needed here (mDialogWindow, mDialog etc...) :

#include <CEGUI/EventArgs.h>  // Used as a reference

#include "CeguiDialog.hpp"

// Forward declarations
namespace Ogre
{
  class Root;
}
class GameEngine;
// End of forward declarations

using namespace std;

class ModalDialog : public CeguiDialog
{
public:
  ModalDialog(const string&, const string&, const string&, const string&);
  ~ModalDialog();

  bool exec(GameEngine*);

protected:
  bool onOk(const CEGUI::EventArgs&);
  bool onCancel(const CEGUI::EventArgs&);
  bool closeDialog(bool);

private:
  bool waiting;
  bool returnValue;
};

Blocking the dialog

Here is the blocking function code :
bool
exec(GameEngine*)
{
  // This boolean must be set to false by a CEGUI slot, for 
  // example the Ok or Cancel buttons slot
  waiting = true;
 
  // Shows the dialog
  mDialogWindow->setVisible(true);
  mDialog->setVisible(true);
  mDialog->activate();
  while (waiting)
    {
      // Tested to make the the GeometryBuffer object appear
      CEGUI::System::getSingleton().getDefaultGUIContext().
        clearGeometry(CEGUI::RQ_OVERLAY);

      // Make Ogre3D render one frame
      Ogre::WindowEventUtilities::messagePump();
      root->renderOneFrame();
    }
  return returnValue;
}

Connecting Ok button

Then, we create a function to connect the OK/close button to, set the dialog return value and set waiting to false :
void
closeDialog(bool value)
{
  waiting = false;
  hide();

  // Set the return value of the dialog
  returnValue = value;
}

bool
CeguiDialog::onOk(const CEGUI::EventArgs&)
{
  closeDialog(true);

  // Tells CEGUI we fully handled the event
  return true;
}

CEGUI::PushButton* btnOk = (CEGUI::PushButton *)mDialogWindow->
    getChild("nyiRoot/winToolbar/btnOk");
btnOk->subscribeEvent(CEGUI::PushButton::EventClicked,
  CEGUI::Event::Subscriber(&CeguiDialog::onOk, this));

Need a Cancel button ?

Adding a cancel button is as simple as adding a CEGUI slot with a different closeDialog parameter value :
bool
CeguiDialog::onCancel(const CEGUI::EventArgs&)
{
  closeDialog(false);
  // Tells CEGUI we fully handled the event
  return true;
}

CEGUI::PushButton* btnCancel = (CEGUI::PushButton *)mDialogWindow->
    getChild("nyiRoot/winToolbar/btnCancel");
btnCancel->subscribeEvent(CEGUI::PushButton::EventClicked, 
    CEGUI::Event::Subscriber(&CeguiDialog::onCancel, this));

Conclusion

This modal dialog, in its current state, event if not perfect, works. If I manage to improve it, I'll try to update this article.

Comments

Popular posts from this blog

How to make a map of variant in C++