Home - Forums - Documentation - Gallery - Bugs
(The event handler section)
Current revision (15:38, 21 July 2008) (edit) (undo)
(Adding some log-related config options)
 
(4 intermediate revisions not shown.)
Line 1: Line 1:
[[Category:Tutorial]]
[[Category:Tutorial]]
-
= Step Four: : Using CEGUI =
+
= Step Four: : Setup the logging system =
== Introduction ==
== Introduction ==
-
In this tutorial we will create our applications’ windows with the help of CEGUI. This tutorial contains basic information only about the library , when CEGUI is new for you, please visit the project website for more information:
+
The ''Crystal Space SDK '' contents a built-in reporter system. You can sending messages to the following places:
-
[http://www.cegui.org.uk www.cegui.org.uk]
+
* stdout : Your message will be sent to the standard output.
 +
* stderr : Your message will be sent to standard error channel.
 +
* alert : Your message will be displayed in a information window.
 +
* console: Your message will be displayed on the console output.
 +
* debug : Your massage will be logged into the debug log file.
 +
* popup :
-
The CS SDK has the '''Ceguitest''' demo, a basic example, how you can integrate CEGUI into your application. The '''viewmesh'' test application uses also CEGUI, here you can find a long and detailed example, how to deal with this impressive windowing system under CS.
+
==Adding some log-related config options ==
-
== Important notes ==
+
Let's create an optional log file. First, we add to our ''cim.cfg'' the following options:
-
 
+
-
Some notes about CEGUI under CS. There is an introduction to Cegui in the manual, please read this section first. I cite the most important section:
+
<pre>
<pre>
-
It is important that applications using CEGUI from Crystal Space do not use any of
+
Cim.Settings.EnableLogging = true
-
the CEGUI getSingleton() or getSingletonPtr() calls, such as
+
Cim.Settings.DebugFileName = /cim/debug.log
-
CEGUI::Singleton<T>::getSingleton() or CEGUI::System::getSingleton(). The reason
+
Cim.Settings.AppendLogFile = false
-
for this is that global and static variables (declared in methods, classes,
+
-
namespaces, or globally) are not normally shared between modules. Calling
+
-
getSingleton() from the Crystal Space application will not necessarily return
+
-
the same instance as calling getSingleton() from the CEGUI plugin.
+
</pre>
</pre>
-
Don't forget to link the CEGUIBase* library, when you build this demo. The correct name is depend on your build system. When you use '''MSVC8''', you need ''CEGUIBase-vc8_d.lib'' (in debug mode) or ''CEGUIBase-vc8.lib '' in release mode. These are in your ''CS\libs\csutil\win32\libs'' folder.
+
When the ''EnableLogging'' option is true, the game writes the report messages in the log file. The ''DebugFileName'' decides the name of the log file. The ''AppendLogFile '' option controls, the app creates a new log file or appends the messages to the old one (if any).
-
 
+
-
 
+
-
== Loading CEGUI plugin ==
+
-
 
+
-
To load CEGUI plugin, first we need change the ''cimGame::OnInitialize '' al little bit:
+
 +
Ok, let's go to load this options in the ''cimGame::LoadConfig()'':
<pre>
<pre>
-
if (!csInitializer::RequestPlugins(object_reg = GetObjectRegistry(),
+
bool cimGame::LoadConfig()
-
CS_REQUEST_VFS,
+
{
-
CS_REQUEST_OPENGL3D,
+
csRef<iConfigManager> confman (CS_QUERY_REGISTRY (GetObjectRegistry(), iConfigManager));
-
CS_REQUEST_ENGINE,
+
startmap = confman->GetStr("Cim.Settings.StartLevel","terrain");
-
CS_REQUEST_FONTSERVER,
+
use_console = confman->GetBool("Cim.Settings.EnableConsole",false);
-
CS_REQUEST_IMAGELOADER,
+
enable_logging = confman->GetBool("Cim.Settings.EnableLogging",false);
-
CS_REQUEST_LEVELLOADER,
+
debug_filename = confman->GetStr("Cim.Settings.DebugFileName","/cim/debug.log");
-
CS_REQUEST_REPORTER,
+
append_logfile = confman->GetBool("Cim.Settings.AppendLogFile",true);
-
CS_REQUEST_REPORTERLISTENER,
+
return true;
-
CS_REQUEST_PLUGIN("crystalspace.collisiondetection.opcode",
+
}
-
iCollideSystem),
+
-
CS_REQUEST_PLUGIN("crystalspace.console.output.standard",
+
-
iConsoleOutput),
+
-
CS_REQUEST_PLUGIN ("crystalspace.cegui.wrapper", iCEGUI),
+
-
CS_REQUEST_END))
+
-
return ReportError("Failed to initialize plugins!");
+
</pre>
</pre>
-
The ''CS_REQUEST_PLUGIN ("crystalspace.cegui.wrapper", iCEGUI)'' will load the CEGUI plugin.
+
== Listening the reports ==
-
We introduce a new class to handle the interface of our game. This new ''cimGuiHandler'' class qwill:
+
''Crystal Space '' provides us the ''iStandardReporterListener'' interface to do this. Let's query this:
-
* initialize CEGUI plugin, loading skin and layouts.
 
-
* render CEGUI interface, show the actual window
 
-
* encapsulate all CEGUI callback functions
 
- 
-
== The header ==
 
<pre>
<pre>
-
class cimGuiHandler
+
listener = CS_QUERY_REGISTRY(GetObjectRegistry(),iStandardReporterListener);
-
{
+
-
public:
+
-
 
+
-
bool Initialize(iObjectRegistry* obj_reg);
+
</pre>
</pre>
-
Yes, initializing. This function will intiailaze CEGUI and the event handler.
 
-
<pre>
+
Ok, we have a the listener, let's customize it. As we said, Crystal Space ensures you many channel to your reports. Crystal Space uses 5 severity level:
-
bool HandleEvent(iEvent& ev);
+
* CS_REPORTER_SEVERITY_BUG: his is the worst thing that can happen. It means that some code detected a bug in Crystal Space.
-
+
* CS_REPORTER_SEVERITY_ERROR: There was an error of some kind. Usually this is an error while reading data.
-
struct EventHandler : public scfImplementation1<EventHandler, iEventHandler>
+
* CS_REPORTER_SEVERITY_WARNING: There was some condition which is non fatal but is suspicious.
-
{
+
-
cimGui* parent;
+
-
EventHandler (cimGui* parent) : scfImplementationType (this),
+
* CS_REPORTER_SEVERITY_NOTIFY: This is for debugging and it will usually generate an entry in some log.
-
parent (parent) {}
+
-
 
+
-
virtual ~EventHandler() {}
+
-
 
+
-
virtual bool HandleEvent (iEvent& e) { return parent->HandleEvent(e); }
+
-
CS_EVENTHANDLER_NAMES("cim.gui")
+
-
CS_EVENTHANDLER_NIL_CONSTRAINTS
+
-
};
+
-
</pre>
+
-
We need an event handler to subscribe to the PostProcess event. We will render cegui in this phase. The solution is same, as in the prvious tutorial.
+
 +
We can define, on what messaging channel listening what severity levels.
 +
iStandardReporterLIstener has a SetMessageDestination function:
<pre>
<pre>
-
private:
+
virtual void SetMessageDestination (int severity,
-
 
+
bool do_stdout, bool do_stderr, bool do_console,
-
bool OnBtnNewGameClicked(const CEGUI::EventArgs&);
+
bool do_alert, bool do_debug, bool do_popup = false) = 0;
-
 
+
-
bool OnBtnLoadGameClicked(const CEGUI::EventArgs&);
+
-
 
+
-
bool OnBtnSettingsClicked(const CEGUI::EventArgs&);
+
-
 
+
-
bool OnBtnExitClicked(const CEGUI::EventArgs&);
+
</pre>
</pre>
-
These are the window callback functions. Ehen the user will push a button on the cegui layout, the corresponding function will be called. Important, that all CEGUI callback function must foloww the following definition:
 
- 
-
<pre>bool MyCEGUIEventHandlerconst CEGUI::EventArgs&);</pre>
 
 +
We want to use the ''standard output'', the ''console'' and the ''debug file''. So the code is:
<pre>
<pre>
-
 
+
listener->SetMessageDestination(CS_REPORTER_SEVERITY_ERROR,true,false,true,false,true,false);
-
iObjectRegistry* object_reg;
+
listener->SetMessageDestination(CS_REPORTER_SEVERITY_WARNING,true,false,true,false,true,false);
-
 
+
listener->SetMessageDestination(CS_REPORTER_SEVERITY_NOTIFY,true,false,true,false,true,false);
-
csEventID FinalProcess;
+
listener->SetMessageDestination(CS_REPORTER_SEVERITY_DEBUG,true,false,true,false,true,false);
-
+
-
csRef<iCEGUI> cegui;
+
-
 
+
-
csRef<EventHandler> eventHandler;
+
</pre>
</pre>
-
We need a pointer to the object registry, (to communicate with the CS framework), a refernce to cegui plugin and the event handler.
+
Now we set up the log filename:
-
 
+
-
== Implementing ''Initalize'' function ==
+
-
 
+
<pre>
<pre>
-
bool cimGuiHandler::Initialize(iObjectRegistry *obj_reg)
+
listener->SetDebugFile(debug_filename,append_logfile);
-
{
+
</pre>
-
object_reg = obj_reg;
+
-
eventHandler.AttachNew (new EventHandler (this));
+
-
csRef<iEventQueue> queue = CS_QUERY_REGISTRY(object_reg, iEventQueue);
+
-
if (queue.IsValid())
+
-
{
+
-
csEventID events[]=
+
-
{
+
-
csevPostProcess(object_reg),
+
-
CS_EVENTLIST_END
+
-
};
+
-
queue->RegisterListener(eventHandler,events);
+
==Time stamps ==
-
}
+
Current date and time is not so important in 3D apps, but a cool looking log file contents the starting time at least in a headline. We write the current date and time into string, using the ''_strdate'' and ''_strtime'' functions (you have to include "time.h"):
-
FinalProcess = csevPostProcess (object_reg);
 
-
</pre>
 
-
TOur event handler will interesting for the Postprocess event. I described the sunscribing mechanism in the previous totorial.
 
<pre>
<pre>
-
//init Cegui plugin
+
char dateStr [9];
-
cegui = CS_QUERY_REGISTRY (object_reg,iCEGUI);
+
char timeStr [9];
-
if (!cegui) return false;
+
_strdate( dateStr);
-
if( !cegui->Initialize() ) return false;
+
_strtime( timeStr );
</pre>
</pre>
-
We query and start Cegui plugin. <br>
 
-
<pre>
 
-
cegui->GetLoggerPtr ()->setLoggingLevel(CEGUI::Informative);
 
-
cegui->GetSchemeManagerPtr ()->loadScheme("Falagard.scheme");
 
-
cegui->GetSystemPtr ()->setDefaultMouseCursor("Falagard", "MouseArrow");
 
-
CEGUI::Font* font = cegui->GetFontManagerPtr ()->createFont("FreeType",
 
-
"Vera", "/fonts/ttf/Vera.ttf");
 
-
font->setProperty("PointSize", "10");
 
-
font->load();
 
- 
-
</pre>
 
-
CEGUI has a builtin logging system. We can choose the needed logging level from this enum:
 
-
<pre>
 
-
enum LoggingLevel
 
-
{
 
-
Errors, //!< Only actual error conditions will be logged.
 
-
Standard, //!< Basic events will be logged (default level).
 
-
Informative, //!< Useful tracing (object creations etc) information will be logged.
 
-
Insane //!< Mostly everything gets logged (use for heavy tracing only, log WILL be big).
 
-
};
 
-
</pre>
 
- 
-
Next we load our scheme file (that describes the skin of our windows), and we set up the mouse cursor. Cegui depends on freetype font, so we load a symphatic one (Vera.ttf).
 
-
== Callback functions ==
+
Ok, now we create a head line, using the date and time info:
<pre>
<pre>
-
//setup CEGUI callback functions
+
csString logStr("---------------------------------------");
-
CEGUI::WindowManager* winMgr = cegui->GetWindowManagerPtr ();
+
logStr+="\n";
-
 
+
logStr+="Cim started at ";
-
// Load layout and set as root
+
logStr+=dateStr;
-
cegui->GetSystemPtr ()->setGUISheet(winMgr->loadWindowLayout("cimmain.xml"));
+
logStr+=" : ";
-
 
+
logStr+=timeStr;
-
//main window
+
-
CEGUI::Window* btn = winMgr->getWindow("BtnNewGame");
+
-
btn->subscribeEvent(CEGUI::PushButton::EventClicked,
+
-
CEGUI::Event::Subscriber(&cimGuiHandler::OnBtnNewGameClicked, this));
+
-
 
+
-
CEGUI::Window* btn = winMgr->getWindow("BtnLoadGame");
+
-
btn->subscribeEvent(CEGUI::PushButton::EventClicked,
+
-
CEGUI::Event::Subscriber(&cimGuiHandler::OnBtnLoadGameClicked, this));
+
-
 
+
-
CEGUI::Window* btn = winMgr->getWindow("BtnSettings");
+
-
btn->subscribeEvent(CEGUI::PushButton::EventClicked,
+
-
CEGUI::Event::Subscriber(&cimGuiHandler::OnBtnSettingsClicked, this));
+
-
 
+
-
CEGUI::Window* btn = winMgr->getWindow("BtnExit");
+
-
btn->subscribeEvent(CEGUI::PushButton::EventClicked,
+
-
CEGUI::Event::Subscriber(&cimGuiHandler::OnBtnExitClicked, this));
+
 +
csReporterHelper::Report(GetObjectRegistry(),CS_REPORTER_SEVERITY_NOTIFY,"cim",logStr.GetData());
 +
}
</pre>
</pre>
 +
Calling the csReporterHelper::Report (or the csReport macro) the head line goes to the log file.
 +
 +
That's it. See the code for all changes. Get the sources from [http://www.crystaldoc.atw.hu/src/cim/step4.zip here]
-
The first version of the main menu will be something, like this:
+
[[Tutorials|Tutorial Home]]
-
 
+
-
[[Image:cim4_1.jpg]]
+
-
 
+
-
I created this "wonderful" interface with the Celayout editor. You can find this application on the cegui website.
+
-
 
+
-
Every button has an unique name. It's important, because the CEGUI windows manager will find our windows by name. This is the right way to subscrie to an CEGUI event:
+
-
 
+
-
CEGUI::Window* btn = winMgr->getWindow("BtnExit");
+
-
btn->subscribeEvent(CEGUI::PushButton::EventClicked,
+
-
CEGUI::Event::Subscriber(&cimGuiHandler::OnBtnExitClicked, this));
+
-
 
+
-
The ''OnBtnExitClicked'' function will be called, when he user clicks on the exit button (name ''BtnExit''). The function will add to the button real functionality.
+
-
 
+
-
== The event handler section ==
+
-
 
+
-
<pre>
+
-
bool cimGuiHandler::HandleEvent(iEvent &ev)
+
-
{
+
-
if (ev.Name == FinalProcess)
+
-
cegui->Render();
+
-
}
+
-
</pre>
+
-
 
+
-
This is easy. Just call the ''Render'' function to render CEGUI interface.
+

Current revision

Contents

Step Four: : Setup the logging system

Introduction

The Crystal Space SDK contents a built-in reporter system. You can sending messages to the following places:

  • stdout : Your message will be sent to the standard output.
  • stderr : Your message will be sent to standard error channel.
  • alert  : Your message will be displayed in a information window.
  • console: Your message will be displayed on the console output.
  • debug  : Your massage will be logged into the debug log file.
  • popup  :

Adding some log-related config options

Let's create an optional log file. First, we add to our cim.cfg the following options:

Cim.Settings.EnableLogging = true
Cim.Settings.DebugFileName = /cim/debug.log
Cim.Settings.AppendLogFile = false

When the EnableLogging option is true, the game writes the report messages in the log file. The DebugFileName decides the name of the log file. The AppendLogFile option controls, the app creates a new log file or appends the messages to the old one (if any).

Ok, let's go to load this options in the cimGame::LoadConfig():

bool cimGame::LoadConfig()
{
	csRef<iConfigManager> confman (CS_QUERY_REGISTRY (GetObjectRegistry(), iConfigManager));
	startmap = confman->GetStr("Cim.Settings.StartLevel","terrain");
	use_console = confman->GetBool("Cim.Settings.EnableConsole",false);
	enable_logging = confman->GetBool("Cim.Settings.EnableLogging",false);
	debug_filename = confman->GetStr("Cim.Settings.DebugFileName","/cim/debug.log");
	append_logfile = confman->GetBool("Cim.Settings.AppendLogFile",true);
	return true;
}

Listening the reports

Crystal Space provides us the iStandardReporterListener interface to do this. Let's query this:

listener = CS_QUERY_REGISTRY(GetObjectRegistry(),iStandardReporterListener);

Ok, we have a the listener, let's customize it. As we said, Crystal Space ensures you many channel to your reports. Crystal Space uses 5 severity level:

  • CS_REPORTER_SEVERITY_BUG: his is the worst thing that can happen. It means that some code detected a bug in Crystal Space.
  • CS_REPORTER_SEVERITY_ERROR: There was an error of some kind. Usually this is an error while reading data.
  • CS_REPORTER_SEVERITY_WARNING: There was some condition which is non fatal but is suspicious.
  • CS_REPORTER_SEVERITY_NOTIFY: This is for debugging and it will usually generate an entry in some log.

We can define, on what messaging channel listening what severity levels. iStandardReporterLIstener has a SetMessageDestination function:

virtual void SetMessageDestination (int severity,
  	bool do_stdout, bool do_stderr, bool do_console,
	bool do_alert, bool do_debug, bool do_popup = false) = 0;

We want to use the standard output, the console and the debug file. So the code is:

listener->SetMessageDestination(CS_REPORTER_SEVERITY_ERROR,true,false,true,false,true,false);
	  listener->SetMessageDestination(CS_REPORTER_SEVERITY_WARNING,true,false,true,false,true,false);
	  listener->SetMessageDestination(CS_REPORTER_SEVERITY_NOTIFY,true,false,true,false,true,false);
	  listener->SetMessageDestination(CS_REPORTER_SEVERITY_DEBUG,true,false,true,false,true,false);

Now we set up the log filename:

listener->SetDebugFile(debug_filename,append_logfile);

Time stamps

Current date and time is not so important in 3D apps, but a cool looking log file contents the starting time at least in a headline. We write the current date and time into string, using the _strdate and _strtime functions (you have to include "time.h"):

char dateStr [9];
	  char timeStr [9];
	  _strdate( dateStr);
	  _strtime( timeStr );

Ok, now we create a head line, using the date and time info:

csString logStr("---------------------------------------");
	  logStr+="\n";
	  logStr+="Cim started at ";
	  logStr+=dateStr;
	  logStr+=" : ";
	  logStr+=timeStr;

	  csReporterHelper::Report(GetObjectRegistry(),CS_REPORTER_SEVERITY_NOTIFY,"cim",logStr.GetData());
  }

Calling the csReporterHelper::Report (or the csReport macro) the head line goes to the log file.


That's it. See the code for all changes. Get the sources from here

Tutorial Home

| Article | Discussion | View source | History |