SFML community forums

General => SFML projects => Topic started by: Zinlibs on November 30, 2010, 05:53:33 pm

Title: Zeven
Post by: Zinlibs on November 30, 2010, 05:53:33 pm
Hello everyone,

After several months of development (and several episodes), I announce the release of the open-source library Zeven.
I'm Thiziri, main coder of the project, and I must thank Danman (a Zinlibs team member) for his help throughout this work, without nothing would have been possible. Thank you buddy.
My thanks also to Lolo (great programmer 8)) for the advice and SFML, who seems well on the way to dethrone SDL in the months to come. :D
Please, forgive me if I don't write english very good, this is not my native langage (I'm french). :oops:

- But in fact, what is Zeven ? :?:

Well, Zeven is an extensible library (based on sigc++), which allow the use of behaviors, triggers and listeners to organize the way events are managed and set some actions in return.

- But, in a simply way ? :oops:

Basically this allows you to assign a behavior to an object, for example, that certain actions are automatically launched when the behavior or a part of the behavior is satisfied.

- Zeven, Why ? :?:

Zeven was born because we needed (the team responsible for the Zinlibs API) to process the events returned by any windowing API / GUI, in a simply way, ergonomic, programmable and modern. In addition, Zeven is modular, allowing you to use modules for each situation. The module allows for example SFML to treat sf::Events, and has many dedicated Auditors and Triggers thoose make your life easier. In addition, Zeven is a contraction of the words Zinlibs and Events.

- What are Listeners and Triggers ? :shock:

Listeners are the smallest elements of Zeven. They are responsible for listening to the event which they are sensitive and initiate action previously defined if they "hear" this particulary event.
Triggers are larger items, they are composed of two or more listeners to manage complex networks (the programmable side of Zeven).
Note that the behavior can manage a complex network (of triggers) too.

- How does the return-actions system work ? :roll:

We think the signals and slots are a necessary evolution in Zeven, so we chose the library sigc++, which is very easy to use, to assign functions (or methods) to each behavior.

- A little piece of code to have an idea of how operate Zeven ? :twisted:

A tutorial is being written on the wiki SFML, and the sample provided on the SVN (http://code.google.com/p/zeven/) repository (GIT soon) allow you to better understand the mechanisms, but here for you (beloved community) an overview of what you can do with Zeven (and especially its sfZeven module) :
Code: [Select]

// Creation of the event handler :
   zin::sfEventHandler& EventHandler = zin::sfEventHandler::GetInstance();

// Creation of a behavior :
zin::Behavior behavior;

// Creation of some pre-programmed triggers :
zin::sfDoubleClickTrigger trigger1;
zin::sfDragAndDropTrigger trigger2;

// Creation of a custom trigger :
zin::sfTrigger trigger3;

// Creation of some listeners :
zin::sfTextEnteredListener listener1(sf::Key::Code::Space);
zin::sfTimeReachedListener listener2(3.54);

// Connection of the listener to the trigger's input :
trigger3.SetInput(listener1);

// Connection of the listener to the triggers's output :
trigger3.SetOutput(listener2);

// Connection of the both listeners each-other (to form a gateway) :
listener1.ConnectTo(listener2); // Note that you can connect as listener as you want !

// Connection of a function to one of the listeners :
listener2.ConnectTo(sigc::ptr_fun(&HelloWorld));

// Creation an area of action :
sf::FloatRect(20, 20, 80, 80) area;

// Settings of the action's area of the triggers :
trigger1.SetArea(area);
trigger2.SetArea(area);

// Connection of the behavior to a trigger :
behavior.ConnectTo(trigger1);

// Connection between the both (to create a chronology) :
trigger1.ConnectTo(trigger2);

// Connection of a function to a pre-programmed trigger :
trigger2.OnRelease(sigc::hide(sigc::ptr_fun(&ExitProgram));

// Register of the triggers by the event handler :
EventHandler.Register(trigger1);
EventHandler.Register(trigger2);
EventHandler.Register(trigger3);

// Creation of a carry event :
sf::Event event;

while( App.GetEvent(event) )
{
// Add an SFML event in the event handler :
EventHandler.Recept(event);

...
}

// Update of the behavior :
behavior.Update(events);


- The final word? :idea:

What is the worst first name that you know in English? (in french, certainly Gertrude) !
No, seriously, your feedbacks are very welcome (if you have), suggestions, ideas for improvement, and issue various modules (in example if you have problems to compile with cmake); I will answer you with pleasure (and Danman).
I hope you will enjoy Zeven; and wish you good luck for all your projects !
Title: Zeven
Post by: Svenstaro on November 30, 2010, 08:10:15 pm
Well, congratulation on your release.

I have to ask though, why did you reinvent the wheel when there are lots of mature solutions available for this particular problem? Qt did it first, then boost.bind/boost.function, then boost signals and boost signals2. There are also quite a bunch of other C++ libraries that provide signals and slots.
Title: Zeven
Post by: Zinlibs on November 30, 2010, 08:46:00 pm
Thanks a lot.

To answer you, I though to be clear : Zeven is not a signal and slot library, it just uses one, called sigc++. The libs which you are talking about are very heavy, and for the people who want make a GUI library or just for someone who programs a game, that is most interesting to use a tiny library like Zeven to interpret the user's events and throw actions in return. In addition, Zeven allow you to build complex listener and trigger networks, I don't think this feature is very common.
Title: Zeven
Post by: danman on November 30, 2010, 08:54:47 pm
It's better to say that Zeven is an automatic contents updater, or also an automatic event processing for example ;) .

it's very simple to use, and make everythings easier.

for example, we would like to connect the draganddrop trigger to a icon move function whenever the icon has been double-clicked.

it's made in 5 lines with zeven, and it's very clean .
Title: Zeven
Post by: Ceylo on November 30, 2010, 09:41:57 pm
Could you provide a simpler example ? (even with fewer features shown)

It's hard to get an idea of how good it is with the sample code you gave.
Title: Zeven
Post by: Zinlibs on November 30, 2010, 11:33:57 pm
Quote from: "Ceylo"
Could you provide a simpler example ? (even with fewer features shown)

It's hard to get an idea of how good it is with the sample code you gave.


Of course, this is a smaller example :
Code: [Select]

   sf::FloatRect area(50, 50, 100, 100);

   zin::sfMouseOverListener mouseOver(area);
   mouseOver.ConnectTo(myMouseOverFunction);

   zin::sfMouseOutListener mouseOut(area);
   mouseOut.ConnectTo(myMouseOutFunction);

// Connect each other :
   mouseOver.ConnectTo(mouseOut);
   mouseOut.ConnectTo(mouseOver);

   zin::sfTextEnteredListener textEntered;
   textEntered.ConnectTo(PtrFun(&myTextEnteredFunction));

   mouseOver.ConnectTo(textEntered);

   zin::sfTrigger trigger;
   trigger.SetInput(mouseOver);
   trigger.SetOutput(textEntered);

   trigger.SetRepeat(true);

   zin::Behavior behavior;
   behavior.ConnectTo(trigger);


With this code you can define an area which is reactive to the mouse hovering, and call function for each state. If the mouse is over the area, you can also press a key and another function will be called. The trigger is repeated to the infinite.
Title: Zeven
Post by: Ceylo on November 30, 2010, 11:49:09 pm
Quote from: "Zinlibs"

Of course, this is a smaller example :
Code: [Select]

   sf::FloatRect area(50, 50, 100, 100);

   zin::sfMouseOverListener mouseOver(area);
   mouseOver.ConnectTo(myMouseOverFunction);

   zin::sfMouseOverListener mouseOut(area);
   mouseOut.ConnectTo(myMouseOutFunction);

// Connect each other :
   mouseOver.ConnectTo(mouseOut);
   mouseOut.ConnectTo(mouseOver);

   zin::sfTextEnteredListener textEntered;
   textEntered.ConnectTo(PtrFun(&myTextEnteredFunction));

   mouseOver.ConnectTo(textEntered);

   zin::sfTrigger trigger;
   trigger.SetInput(mouseOver);
   trigger.SetOutput(textEntered);

   trigger.SetRepeat(true);

   zin::Behavior behavior;
   behavior.ConnectTo(trigger);


With this code you can define an area which is reactive to the mouse hovering, and call function for each state. If the mouse is over the area, you can also press a key and another function will be called. The trigger is repeated to the infinite.

Well... I was expecting something even shorter and simpler that this. What would be the comprehensive usable example if I wanted to display "hello" to the standard output each time the mouse enters an area ?
Title: Zeven
Post by: Zinlibs on December 01, 2010, 12:21:37 am
Ha peuchère, I'm really complicated, I know ! :D
A very tiny example for you this time :

Code: [Select]
  void Hello()
   {
      std::cout << "Hello world !" << std::endl;
   }

   sf::FloatRect area(0, 0, 100, 100);

   zin::sfMouseOverListener mouseOver(area);
   mouseOver.ConnectTo(PtrFun(&Hello));

   mouseOver.Update(...);


Is this enough short for you ?  :P
Title: Zeven
Post by: Ceylo on December 01, 2010, 12:42:36 am
Short enough, but not usable as it's written (yeah I know I'm demanding :D ). I would like to see the full source code, especially to see how this is integrated in the event loop (your first example in this topic shows an Update() call outside of the main loop and I got puzzled...).
Title: Zeven
Post by: Zinlibs on December 01, 2010, 12:57:38 am
Zeven for dummies :  :lol:

Code: [Select]
////////////////////////////////////////////////////////////
/// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics.hpp>
#include <iostream>
#include <sfModule/sfZeven.hpp>

void Hello()
{
std::cout << "Hello world" << std::endl;
}

////////////////////////////////////////////////////////////
/// Entry point of the application
////////////////////////////////////////////////////////////
int main()
{

// Creation and settings of the SFML rendering window
sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Zeven sample");

// Limitation of the framerate
App.SetFramerateLimit(40);

// Creation of the area
sf::FloatRect area(0, 0, 100, 100);

// Creation of a shape which represent the area
sf::Shape::Rectangle rectangle(area.Left, area.Top, area.Width, area.Height, sf::Color::Red);

// Creation of the mouse over listener
zin::sfMouseOverListener mouseOver(area);

// Connection to the function Hello
    mouseOver.ConnectTo(PtrFun(&Hello));

// Main process loop
while( App.IsOpened() )
{

// Rest of the processor
sf::Sleep(0.02);

// Create an empty event
sf::Event Event;

// Create an event container
zin::sfEvents Events;
Events.SendMousePos(App.ConvertCoords(App.GetInput().GetMouseX(), App.GetInput().GetMouseY()));

// Event loop
while( App.GetEvent(Event) )
{
// Add the event into the container
Events+=Event;

// Close window to exit the program
if( Event.Type == sf::Event::Closed )
App.Close();

// Esc to exit the program
if( Event.Type == sf::Event::KeyPressed && Event.Key.Code == sf::Key::Escape )
App.Close();
}

// Send the events to the listener
mouseOver.Update(Events);

// Clear the screen
App.Clear();

// Add drawable in the stack
App.Draw(rectangle);

// Displaying in the rendering window
App.Display();
}

return EXIT_SUCCESS;
}
Title: Zeven
Post by: Svenstaro on December 01, 2010, 06:38:46 am
I see, I shall take a look at this more thoroughly. Can you translate your code comments to English on SVN?
Title: Zeven
Post by: Zinlibs on December 01, 2010, 08:22:22 am
OK, I will do this as soon as possible.
Title: Zeven
Post by: Zinlibs on December 01, 2010, 12:16:47 pm
Translation done.
Title: Zeven
Post by: Ceylo on December 01, 2010, 01:40:45 pm
From what I understood in your sample code :

1. You need to call Update() for each listener.
2. You need to manually append each event to your events' container.
3. You need to go through your own container to do the Update() call.

Wouldn't it be possible to do something like :
Code: [Select]

while ( window_opened )
{
    while ( get_event(ev) )
    {
        zin::EventHandler::readEvent(ev);

        // other event handling stuff
    }
}

No update, no manual event container handling, and the event is automatically sent to all of the listeners.

What's your thought about this ?
Title: Zeven
Post by: Zinlibs on December 01, 2010, 02:41:45 pm
This is a good observation and remark, and need answer point by point :

Quote
1. You need to call Update() for each listener.


Yes, in this case, but you can also use Trigger to register an input listener, connected to a potential listeners network. If a listener is listened, its targets (some other listeners connected) will be updated at their turn. But if one of them is listened, the other will be no longer updated. The same applies to Behavior and Trigger. Finaly, you just have to update one Behavior, one Trigger, or one Listener, that depends only of you needs.

Quote
2. You need to manually append each event to your events' container.
3. You need to go through your own container to do the Update() call.


I concede that an events' container is not an elegant and clean solution. This is a temporary one since the begining. I'm currently working on it.

Quote
What's your thought about this ?


I like it. Danman submit another one. At this time, no choice is made. I just trying to find the best solution and avoid new problems. Concider for example there aren't just sf::Event listeners in the sfListener, you have sfTimeReachedListener (with an internal clock), sfMouseOver/OutListener too, and those ones need a real-time update.

It might take an undefined time, but It's sure, I will improve the current updating system as best I can. Thanks a lot for your interest Ceylo.
Title: Zeven
Post by: nfries88 on December 03, 2010, 01:14:46 am
I have to say that this doesn't look very useful to someone who is not looking for a robust and flexible structure to their code, which may be why Ceylo doesn't get the point in it.

Or it may be the fact that the need to append your event structure with every event received and the update methods, as he pointed out, make the solution slightly less robust.

What exactly do these update functions do?
Title: Zeven
Post by: Zinlibs on December 06, 2010, 01:10:28 pm
Sorry if I don't have responded earlier, but the method of update has just been improved. For the moment, it is just an overlay of the current public interface, and the performances are lower than before. If you approve the new system, I will adapt the code to no longer use the Events class, and the performances should return to the normal. Here are the changes :

Code: [Select]

////////////////////////////////////////////////////////////
/// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics.hpp>
#include <iostream>
#include <Zeven/sfZeven/sfZeven.hpp>

void Hello()
{
   std::cout << "Hello world" << std::endl;
}

////////////////////////////////////////////////////////////
/// Entry point of the application
////////////////////////////////////////////////////////////
int main()
{

// Creation and settings of the SFML rendering window
   sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Zeven sample");
   
// Limitation of the framerate
   App.SetFramerateLimit(40);

// Creation of the area
   sf::FloatRect area(0, 0, 100, 100);

// Creation of a shape which represent the area
   sf::Shape::Rectangle rectangle(area.Left, area.Top, area.Width, area.Height, sf::Color::Red);

// Get the event handler
   zin::sfEventHandler<zin::sfListener>& EventHandler = zin::sfEventHandler::GetInstance();

// Creation of the mouse over listener
   zin::sfMouseOverListener mouseOver(area);

// Connection to the function Hello
    mouseOver.ConnectTo(sigc::ptr_fun(&Hello));

// Register the listener
    EventHandler.Register(mouseOver);

// Main process loop
   while( App.IsOpened() )
   {
       
   // Rest of the processor
      sf::Sleep(0.02);
       
   // Create an empty event
      sf::Event Event;

   // Event loop
      while( App.GetEvent(Event) )
      {
      // Send an SFML event to the event handler
         EventHandler.Recept(Event);
         
      // Close window to exit the program
         if( Event.Type == sf::Event::Closed )
            App.Close();
       
      // Esc to exit the program
         if( Event.Type == sf::Event::KeyPressed && Event.Key.Code == sf::Key::Escape )
            App.Close();
      }

   // Send the mouse position
      EventHandler.Recept(App.ConvertCoords(App.GetInput().GetMouseX(), App.GetInput().GetMouseY()));

   // Update the event handler
      EventHandler.Update();

   // Clear the screen
      App.Clear();
       
   // Add drawable in the stack
      App.Draw(rectangle);
       
   // Displaying in the rendering window
      App.Display();
   }

   return EXIT_SUCCESS;
}