Difference between revisions of "Cool window effects"

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search
(Inactive windows become transparent)
 
(16 intermediate revisions by 6 users not shown)
Line 1: Line 1:
 
= Inactive windows become transparent =
 
= Inactive windows become transparent =
Please discuss this snippet within the [[http://www.cegui.org.uk/phpBB2/viewtopic.php?p=11786 cool window effects - Inactive windows become trans.]] thread.  
+
 
 +
Please discuss this snippet within the [http://www.cegui.org.uk/phpBB2/viewtopic.php?p=11786 cool window effects - Inactive windows become trans.] thread.  
  
 
Do you know about the [http://vizzzion.org/images/blog/composite.png cool effects that the composite extension can create] on linux ? There are many. I wanted to implement one into my game: make the [http://img337.imageshack.us/img337/9398/windowtransparencyue1.png inactive windows become transparent] and only the active one be 100% opaque. (see the links in this sentence for screenshots.) This effect can be interesting if you want your users to concentrate 100% on the active window and the inactive ones aren't important at this moment. But what if the user has to see two windows or more at the same time (and with full opacity) ? We'll see how to handle this.
 
Do you know about the [http://vizzzion.org/images/blog/composite.png cool effects that the composite extension can create] on linux ? There are many. I wanted to implement one into my game: make the [http://img337.imageshack.us/img337/9398/windowtransparencyue1.png inactive windows become transparent] and only the active one be 100% opaque. (see the links in this sentence for screenshots.) This effect can be interesting if you want your users to concentrate 100% on the active window and the inactive ones aren't important at this moment. But what if the user has to see two windows or more at the same time (and with full opacity) ? We'll see how to handle this.
Line 7: Line 8:
 
There is more then one way to achieve this, but I'll only present the one I chose. CEGUI has something that is called global events. These are events that are fired independently on the widget they apply to. I'll try with an example: sometimes you need to know when a button is clicked, no matter what button it is, you want to know it for EVERY button. This is what global events are for.
 
There is more then one way to achieve this, but I'll only present the one I chose. CEGUI has something that is called global events. These are events that are fired independently on the widget they apply to. I'll try with an example: sometimes you need to know when a button is clicked, no matter what button it is, you want to know it for EVERY button. This is what global events are for.
  
We'll subscribe to two global events: "a window gets activated" and "a window gets closed". When a window gets activated, we add it to a stack wich we use to keep track of the windows and the order they where activated. We also make the last active window become transparent. When a window gets closed, we remove it from the stack and activate the one that is on the top of the stack now. (that is the window that was active just before the one we just closed.)
+
We'll subscribe to two global events: "a window gets activated" and "a window gets closed". When a window gets activated, we add it to a stack which we use to keep track of the windows and the order they where activated. We also make the last active window become transparent. When a window gets closed, we remove it from the stack and activate the one that is on the top of the stack now. (that is the window that was active just before the one we just closed.)
 +
 
 +
We keep the root window away from it, that means we never make the root window transparent, because this would make the tooltips become transparent. You need to have an empty root window that is a container for your other windows.
  
 
== The praxis (code) ==
 
== The praxis (code) ==
 
Now let's go ! First, we need to register callback functions to the two global events:
 
Now let's go ! First, we need to register callback functions to the two global events:
<code><cpp/>
+
<source lang="cpp">
 
CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( CEGUI::Window::EventNamespace + "/" + CEGUI::Window::EventActivated,
 
CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( CEGUI::Window::EventNamespace + "/" + CEGUI::Window::EventActivated,
 
                                                       CEGUI::Event::Subscriber(&onWindowActivated) );
 
                                                       CEGUI::Event::Subscriber(&onWindowActivated) );
 
CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( CEGUI::Window::EventNamespace + "/" + CEGUI::Window::EventDestructionStarted,
 
CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( CEGUI::Window::EventNamespace + "/" + CEGUI::Window::EventDestructionStarted,
                                                       CEGUI::Event::Subscriber(&onWindowClosed) );</code>
+
                                                       CEGUI::Event::Subscriber(&onWindowClosed) );</source>
  
 
We also need a stack to keep track of the windows. I chose to use the std::list type instead of the std::stack, because we need to be able to either delete all references of one element or to search the stack. So here it is:
 
We also need a stack to keep track of the windows. I chose to use the std::list type instead of the std::stack, because we need to be able to either delete all references of one element or to search the stack. So here it is:
<code><cpp/>std::list<CEGUI::Window *> pWinHistory;</code>
+
<source lang="cpp">std::list<CEGUI::Window *> pWinHistory;</source>
 +
 
 +
Also, don't forget to put your root window just before setting it as the root window:
 +
<source lang="cpp">pWinHistory.push_back(pMyRootWindow);
 +
CEGUI::System::getSingleton().setGUISheet(pMyRootWindow);
 +
</source>
 +
 
 +
One thing you need to know about the root window is that you need an empty root window, containing one or more child windows that contain all GUI items. Your root window will never become transparent, thus you need an empty "container" root window.
  
 
And now we implement our two callback functions. I excessively commented the functions.
 
And now we implement our two callback functions. I excessively commented the functions.
  
 
onWindowActivated:
 
onWindowActivated:
<code><cpp/>/// Called everytime a window gets activated.
+
<source lang="cpp">/// Called everytime a window gets activated.
 
/** This function is called by CEGUI every time that a window gets the focus.
 
/** This function is called by CEGUI every time that a window gets the focus.
 
  *
 
  *
Line 50: Line 60:
 
return true;
 
return true;
  
// If every time a window gets activated we make the last active window become
+
if( pLastWin != CEGUI::System::getSingleton().getGUISheet() ) {
// transparent, this will result in all inactive windows being transparent.
+
// If every time a window gets activated we make the last active window become
pLastWin->setProperty( "Alpha", "0.25" );
+
// transparent, this will result in all inactive windows being transparent.
 +
pLastWin->setProperty( "Alpha", "0.25" );
 +
 
 +
// But we never make the root window transparent, as this would make all tooltips
 +
// become transparent, and we don't want this !
 +
}
  
 
// We need the active window to not inherit the transparence of its parents.
 
// We need the active window to not inherit the transparence of its parents.
Line 69: Line 84:
  
 
return true;
 
return true;
}</code>
+
}</source>
  
 
And onWindowClosed:
 
And onWindowClosed:
<code><cpp/>/// Called everytime a window gets closed.
+
<source lang="cpp">/// Called everytime a window gets closed.
 
/** This function is called by CEGUI just before a window gets closed.
 
/** This function is called by CEGUI just before a window gets closed.
 
  *
 
  *
Line 116: Line 131:
  
 
return true;
 
return true;
}</code>
+
}</source>
  
 
That's all.
 
That's all.
Line 126: Line 141:
 
Edit: Hmm I tried this one but wasn't able to get it to work. If someone has success, please tell us how you did it in the forums.
 
Edit: Hmm I tried this one but wasn't able to get it to work. If someone has success, please tell us how you did it in the forums.
  
* You could try to make the window's transparency degree dependent on it's position in the stack. That means the most recent windows get less transparent while the "oldest" windows get very transparent. To do this, just loop trough the stack - that would be a list - and set every window's transparency accordingly. Do this when a window gets active AND when a window gets closed. You would also need to never have the same window twice in the stack, as it would screw your results up.
+
* You could try to make the window's transparency degree dependent on its position in the stack. That means the most recent windows get less transparent while the "oldest" windows get very transparent. To do this, just loop trough the stack - that would be a list - and set every window's transparency accordingly. Do this when a window gets active AND when a window gets closed. You would also need to never have the same window twice in the stack, as it would screw your results up.
  
  
--[[User:Pompei2|Pompei2]] 06:00, 6 May 2007 (PDT)
+
--[[User:Pompei2]] 06:00, 6 May 2007 (PDT)
  
  
Line 135: Line 150:
 
----
 
----
 
you can add more cool effects here.
 
you can add more cool effects here.
 +
 +
[[Category:Tutorials]]

Latest revision as of 20:24, 4 March 2011

Inactive windows become transparent

Please discuss this snippet within the cool window effects - Inactive windows become trans. thread.

Do you know about the cool effects that the composite extension can create on linux ? There are many. I wanted to implement one into my game: make the inactive windows become transparent and only the active one be 100% opaque. (see the links in this sentence for screenshots.) This effect can be interesting if you want your users to concentrate 100% on the active window and the inactive ones aren't important at this moment. But what if the user has to see two windows or more at the same time (and with full opacity) ? We'll see how to handle this.

The theory

There is more then one way to achieve this, but I'll only present the one I chose. CEGUI has something that is called global events. These are events that are fired independently on the widget they apply to. I'll try with an example: sometimes you need to know when a button is clicked, no matter what button it is, you want to know it for EVERY button. This is what global events are for.

We'll subscribe to two global events: "a window gets activated" and "a window gets closed". When a window gets activated, we add it to a stack which we use to keep track of the windows and the order they where activated. We also make the last active window become transparent. When a window gets closed, we remove it from the stack and activate the one that is on the top of the stack now. (that is the window that was active just before the one we just closed.)

We keep the root window away from it, that means we never make the root window transparent, because this would make the tooltips become transparent. You need to have an empty root window that is a container for your other windows.

The praxis (code)

Now let's go ! First, we need to register callback functions to the two global events:

CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( CEGUI::Window::EventNamespace + "/" + CEGUI::Window::EventActivated,
                                                       CEGUI::Event::Subscriber(&onWindowActivated) );
CEGUI::GlobalEventSet::getSingleton( ).subscribeEvent( CEGUI::Window::EventNamespace + "/" + CEGUI::Window::EventDestructionStarted,
                                                       CEGUI::Event::Subscriber(&onWindowClosed) );

We also need a stack to keep track of the windows. I chose to use the std::list type instead of the std::stack, because we need to be able to either delete all references of one element or to search the stack. So here it is:

std::list<CEGUI::Window *> pWinHistory;

Also, don't forget to put your root window just before setting it as the root window:

pWinHistory.push_back(pMyRootWindow);
CEGUI::System::getSingleton().setGUISheet(pMyRootWindow);

One thing you need to know about the root window is that you need an empty root window, containing one or more child windows that contain all GUI items. Your root window will never become transparent, thus you need an empty "container" root window.

And now we implement our two callback functions. I excessively commented the functions.

onWindowActivated:

/// Called everytime a window gets activated.
/** This function is called by CEGUI every time that a window gets the focus.
 *
 *  Currently, we use this function to keep track of the order that windows where
 *  active, so when closing a window we can activate the last one, as this isn't
 *  done automatically by CEGUI.
 *
 * \param e The event arguments.
 *
 * \return Always true.
 *
 * \author Pompei2
 */
bool onWindowActivated( const CEGUI::EventArgs &ea )
{
	try {
		const CEGUI::WindowEventArgs& we = static_cast<const CEGUI::WindowEventArgs&>(ea);
		CEGUI::Window *pLastWin = pWinHistory.back( );
 
		// We only work with FrameWindows.
		if( !we.window->testClassName( CEGUI::FrameWindow::EventNamespace ) )
			return true;
 
		// If it is the same window as before, ignore it.
		if( pLastWin == we.window )
			return true;
 
		if( pLastWin != CEGUI::System::getSingleton().getGUISheet() ) {
			// If every time a window gets activated we make the last active window become
			// transparent, this will result in all inactive windows being transparent.
			pLastWin->setProperty( "Alpha", "0.25" );
 
			// But we never make the root window transparent, as this would make all tooltips
			// become transparent, and we don't want this !
		}
 
		// We need the active window to not inherit the transparence of its parents.
		we.window->setProperty( "InheritsAlpha", "false" );
 
		// Finally, we add the new window to the stack.
 
		// One could also check if it's already present in the stack and if yes, just put it on the top.
		// You would have to do this if you want to set the transparency depending on the window's position
		// in the stack (see "Extending the effect").
		pWinHistory.push_back( we.window );
 	} catch( CEGUI::Exception& e ) {
		fprintf( stderr, "CEGUI error: %s\n", e.getMessage( ).c_str( ) );
		return true;
	}
 
	return true;
}

And onWindowClosed:

/// Called everytime a window gets closed.
/** This function is called by CEGUI just before a window gets closed.
 *
 *  Currently, we use this function to activate the previous window
 *  when closing this one, as it's not done automatically by CEGUI.
 *
 * \param e The event arguments.
 *
 * \return Always true.
 *
 * \author Pompei2
 */
bool onWindowClosed( const CEGUI::EventArgs &ea )
{
	try {
		const CEGUI::WindowEventArgs& we = static_cast<const CEGUI::WindowEventArgs&>(ea);
		CEGUI::Window *pLastWin = NULL;
 
		// We only work with FrameWindows.
		if( !we.window->testClassName( CEGUI::FrameWindow::EventNamespace ) )
			return true;
 
		// Delete the current window from the stack.
		// CARE: std::list::remove removes ALL occurences of we.window from the stack !
		// This is VERY important to know, as if you activate window A, then window B and then A again,
		// the stack will contain A twice: {A,B,A}.
		pWinHistory.remove( we.window );
 
		// Now we get the window that was active before the current one:
		pLastWin = m_pWinHistory.back( );
 
		// re-activate it (like windos, linux, .. all do).
		pLastWin->activate( );
 
		// And set it to be opaque again.
		// You could either do this here or you do this in the onWindowActivate function, the result is the same,
		// as the call to CEGUI::Window::activate above results in onWindowActivate to be called.
		pLastWin->setProperty( "Alpha", "1.0" );
	} catch( CEGUI::Exception& e ) {
		fprintf( stderr, "CEGUI error: %s\n", e.getMessage( ).c_str( ) );
		return true;
	}
 
	return true;
}

That's all.

One important thing you might not know yet, is that CEGUI DOESN'T activate a window that gets shown. you have to manually activate a window when you create it (and want it to be active, of course).

Extending the effect

  • You could also automatically activate a window as soon as it's shown. for this you could subscribe to the "a window gets shown" global event and then just call ea.window->activate( );

Edit: Hmm I tried this one but wasn't able to get it to work. If someone has success, please tell us how you did it in the forums.

  • You could try to make the window's transparency degree dependent on its position in the stack. That means the most recent windows get less transparent while the "oldest" windows get very transparent. To do this, just loop trough the stack - that would be a list - and set every window's transparency accordingly. Do this when a window gets active AND when a window gets closed. You would also need to never have the same window twice in the stack, as it would screw your results up.


--User:Pompei2 06:00, 6 May 2007 (PDT)




you can add more cool effects here.