SDL GUI?

Started by
6 comments, last by nfries88 12 years, 11 months ago
Can you make your GUI with SDL? Or would it be better to use like Win32+SDL
Advertisement
It's been a while since I used SDL (and have not tried 1.3 -- is it available?), but I think part of the whole point of SDL is to avoid using the Win32 APIs and instead simplify access to (typically game) I/O in a cross-platform way. There's also some higher-level functionality like a 2D engine, but I don't believe there's any GUI API built-in. There might be add-on libraries or GUI libraries designed to work with SDL...

A common approach with games is to use custom GUI widgets rather than the OS-native ones (though it really depends on the game). There are also other frameworks like Tk that are designed to create GUI applications... maybe you could find some mix of framework/libraries that get you running quick.
Yes you can make your game's GUI with SDL and no, IMHO, it would not be better to use Win32 API. I wrote my own. But I'm using OpenGL instead of SDL. When I first started creating and GUI, I found it much easier and faster using SDL because it got the event handling and drawing bits out of the way for me. Just simple colored rectangles and crap but it worked they responded to the mouse as desired. A GUI is surprisingly easy to create. It gets more complex as you progress to more interesting controls(or widgets, as stated by the other guy) such as list controls, combo boxes or grids. SDL can really boost the development here because, like I said, it handles events and provides you with simple drawing mechanisms. I believe there are tutorials here on gamedev.... its been a long time since I looked at em' though. I also found this site on google. Hope this helps.

Yes you can make your game's GUI with SDL and no, IMHO, it would not be better to use Win32 API. I wrote my own. But I'm using OpenGL instead of SDL. When I first started creating and GUI, I found it much easier and faster using SDL because it got the event handling and drawing bits out of the way for me. Just simple colored rectangles and crap but it worked they responded to the mouse as desired. A GUI is surprisingly easy to create. It gets more complex as you progress to more interesting controls(or widgets, as stated by the other guy) such as list controls, combo boxes or grids. SDL can really boost the development here because, like I said, it handles events and provides you with simple drawing mechanisms. I believe there are tutorials here on gamedev.... its been a long time since I looked at em' though. I also found this site on google. Hope this helps.


It does help thank you, and SDL_ttf is the only way to draw text on the screen with SDL right? I also heard it's impossible to do check box's or scrolls menus with SDL or is it just much more difficult I suppose anything is possible all you'd really have to do is have a plain, square box appear where you need it to have SDL_ttf write the words on it compose the box as several buttons n then you got your scroll down box or whatever you want to call it.

[quote name='mind_wipe' timestamp='1303100247' post='4799753']
Yes you can make your game's GUI with SDL and no, IMHO, it would not be better to use Win32 API. I wrote my own. But I'm using OpenGL instead of SDL. When I first started creating and GUI, I found it much easier and faster using SDL because it got the event handling and drawing bits out of the way for me. Just simple colored rectangles and crap but it worked they responded to the mouse as desired. A GUI is surprisingly easy to create. It gets more complex as you progress to more interesting controls(or widgets, as stated by the other guy) such as list controls, combo boxes or grids. SDL can really boost the development here because, like I said, it handles events and provides you with simple drawing mechanisms. I believe there are tutorials here on gamedev.... its been a long time since I looked at em' though. I also found this site on google. Hope this helps.


It does help thank you, and SDL_ttf is the only way to draw text on the screen with SDL right? I also heard it's impossible to do check box's or scrolls menus with SDL or is it just much more difficult I suppose anything is possible all you'd really have to do is have a plain, square box appear where you need it to have SDL_ttf write the words on it compose the box as several buttons n then you got your scroll down box or whatever you want to call it.
[/quote]

You can make sliders(scroll bars) in SDL. I've done it. Scrolling windows or content is a little tricky but not as hard as you think. I use the same mechanism to clip children widget's with their parent widgets position and size. I use glScissor to do this. SDL may have a similar feature using clipping rectangles or something along those lines. What I would start of with is redraw the content each frame using the clipping rectangle like glScissor. Every time you're scrollbar is moved adjust the position of the child widgets' and/or content. This should give the allusion of a scrolling pane. Not the most optimized solution but it works.

I use OpenGL and X11 directly. I've noticed that X11 and SDL's event structure is very similar. For me, that made switching things over to pure X and GLX very easy. But trust me, it can be done!

[quote name='Tivoilos' timestamp='1303162898' post='4800072']
[quote name='mind_wipe' timestamp='1303100247' post='4799753']
Yes you can make your game's GUI with SDL and no, IMHO, it would not be better to use Win32 API. I wrote my own. But I'm using OpenGL instead of SDL. When I first started creating and GUI, I found it much easier and faster using SDL because it got the event handling and drawing bits out of the way for me. Just simple colored rectangles and crap but it worked they responded to the mouse as desired. A GUI is surprisingly easy to create. It gets more complex as you progress to more interesting controls(or widgets, as stated by the other guy) such as list controls, combo boxes or grids. SDL can really boost the development here because, like I said, it handles events and provides you with simple drawing mechanisms. I believe there are tutorials here on gamedev.... its been a long time since I looked at em' though. I also found this site on google. Hope this helps.


It does help thank you, and SDL_ttf is the only way to draw text on the screen with SDL right? I also heard it's impossible to do check box's or scrolls menus with SDL or is it just much more difficult I suppose anything is possible all you'd really have to do is have a plain, square box appear where you need it to have SDL_ttf write the words on it compose the box as several buttons n then you got your scroll down box or whatever you want to call it.
[/quote]

You can make sliders(scroll bars) in SDL. I've done it. Scrolling windows or content is a little tricky but not as hard as you think. I use the same mechanism to clip children widget's with their parent widgets position and size. I use glScissor to do this. SDL may have a similar feature using clipping rectangles or something along those lines. What I would start of with is redraw the content each frame using the clipping rectangle like glScissor. Every time you're scrollbar is moved adjust the position of the child widgets' and/or content. This should give the allusion of a scrolling pane. Not the most optimized solution but it works.

I use OpenGL and X11 directly. I've noticed that X11 and SDL's event structure is very similar. For me, that made switching things over to pure X and GLX very easy. But trust me, it can be done!
[/quote]

Well I wont need a scrolling bar(for now) what I really need to be able to do is a edit control box(text input) Is that possible with SDL?
Yes! All you controls that you would prolly ever need, you could write using SDL. Check it, most of my controls started out as simple C structures (e.g. struct widget_t). I used global functions that delegated the events from SDL to my widgets. I then used SDL to draw the controls. So most of the programming for the GUI was most just simple logic.

Let me break it down to you this way. GUIs are simple. If you can draw a sprite, you can draw a GUI. If you can parse, or retrieve input states in some way you can *power* a GUI. It's that simple! Take the sample:



// part logic and render states
//
#define MAX_STRING 256

typedef enum
{
WS_HIDDEN = 1,
WS_ENABLE,
WS_HOT,
WS_SELECT
} WidgetState_s ;

typedef struct
{
SDL_Rect rc ;
SDL_Rect clipmask ;
char text[ MAX_STRING ] ;
WidgetState_s state ;
} Widget_t ;


// draws widget in current state
//
void DrawWidget( Widget* widget )
{
// TODO: Insert custom sprite drawing. But for now, use ugly colored rects
switch ( w->state )
{
case WS_HIDDEN :
// TODO : No drawing hidden widgets!
return ;

case WS_ENABLE :
// TODO : Draw in default state
break ;

case WS_HOT :
// TODO : A.K.A. Hot tracking... So highlight it
break ;

case WS_SELECT :
// TODO : Draw in selection state. For buttons and the like, this is
// the down state.
break ;
}
}


// handle SDL's events
//
void HandleEvents( SDL_Event* event, Widget* widget )
{
switch ( event->type )
{
case SDL_MOUSEMOTION :
// TODO : Handle motion events. I've used this notification for
// dragging mouse enter/exit handlers that I created for my
// widgets.
break ;

case SDL_MOUSEBUTTONDOWN :
case SDL_MOUSEBUTTONUP :
// TODO : Handle button events. I've used this notification to
// trigger the drag events and a widget's WS_SELECT state.

// NOTE : One nice thing about SDL is that it handles the mouse's
// wheel in these notifications too. So you can kill two birds
// with one stone here.
break ;

case SDL_KEYDOWN :
case SDL_KEYUP :
// TODO : Handle keyboard events(i.e. change selections, insert text).
// To add text, I've just appended *character* value of the
// key being pressed + a null terminator to a widget's text.
// Hey, it works at least...
break ;
}
}


I just wrote that... I haven't use SDL in such a long time I had to Google the docs again. Anyways, that is what I'm talking about. I didn't really want to cheat you or anything, so I left a lot of things with TODO and NOTE. But basically that is what I started with. Now, I use classes and I've wrote my own event handling that translates X11 events to my event scheme. You get the idea, right? Its actually very simple. Bound checking for the mouse is really simple too! I just use axis-aligned bounding boxed or AABB via:


bool Widget::InWidget( long lX, long lY )
{
if ( lX < m_lX )
return false ;
else
if ( lX > m_lX + m_uSizeX )
return false ;
else
if ( lY < m_lY )
return false ;
else
if ( lY > m_lY + m_uSizeY )
return false ;

return true ;
}


This is my event handling function as it sits now. It's virtual and calls virtual On*event-name* methods so that derived classes can use this functionality with out getting in the way or screwing up the base functionality.


bool Widget::HandleEvent( IEvent* pEvent )
{
WidgetEvent* pWidgetEvent ;

if ( IsHidden( ) || !IsEnable( ) )
return false ;

if ( NULL != ( pWidgetEvent = ( *pEvent ) ) )
{
switch ( pEvent->GetVerb( ) )
{
case WM_MOUSEMOVE :
if ( m_bMouseDragging )
{
pWidgetEvent->lX -= m_lX ;
pWidgetEvent->lY -= m_lY ;
OnMouseDrag( pWidgetEvent->lX, pWidgetEvent->lY ) ;

Delegates( pEvent ) ;

return true ;
}

if ( InWidget( pWidgetEvent->lX, pWidgetEvent->lY ) )
{
pWidgetEvent->lX -= m_lX ;
pWidgetEvent->lY -= m_lY ;

if ( IsActive( ) )
OnMouseMove( pWidgetEvent->lX, pWidgetEvent->lY ) ;

else
{
SetActive( ) ;
OnMouseOver( pWidgetEvent->lX, pWidgetEvent->lY ) ;
OnMouseMove( pWidgetEvent->lX, pWidgetEvent->lY ) ;
}

Delegates( pEvent ) ;

return true ;
}
else
if ( m_uState & WSTATE_ACTIVE && !m_bMouseDragging )
{
SetActive( false ) ;

pWidgetEvent->lX -= m_lX ;
pWidgetEvent->lY -= m_lY ;

OnMouseExit( pWidgetEvent->lX, pWidgetEvent->lY ) ;

Delegates( pEvent ) ;

return true ;
}
break ;

case WM_MOUSEDOWN :
if ( InWidget( pWidgetEvent->lX, pWidgetEvent->lY ) )
{
SetSelect( ) ;

m_bMouseDragging = true ;

pWidgetEvent->lX -= m_lX ;
pWidgetEvent->lY -= m_lY ;

OnMouseDown( pWidgetEvent->lX, pWidgetEvent->lY, pWidgetEvent->uButton ) ;

Delegates( pEvent ) ;

return true ;
}
break ;

case WM_MOUSEUP :
if ( InWidget( pWidgetEvent->lX, pWidgetEvent->lY ) || IsSelect( ) )
{
SetSelect( false ) ;

m_bMouseDragging = false ;

pWidgetEvent->lX -= m_lX ;
pWidgetEvent->lY -= m_lY ;

OnMouseUp( pWidgetEvent->lX, pWidgetEvent->lY, pWidgetEvent->uButton ) ;

if ( m_uStyle & WSTYLE_NOTIFY && m_pOwner )
m_pOwner->Notify( m_ID ) ;

Delegates( pEvent ) ;

return true ;
}
break ;

// sub-class specific
default :
return Delegates( pEvent ) ;
}
}

return false ;
}


So that's how I do that. My code may not look or be the best but it does worl. As I have tested it many times.

May I suggest that if you do use classes as I have now, and you do have virtual Update, HandleEvents or Render methods for them. Also define a virtual OnPaint method as I have. I have found, that it was helpful when implementing the parent/child relationship in the widgets. The default behavior for Widget::Render() will loop through all the children and draw them via OnPaint. It event calls it's own OnPaint. The kinda abstracted me from have to rewrite so many child-safe code. Here is what I have:


void Widget::Render( void )
{
int vViewport[ 4 ] ;
Widget* pChild ;

if ( IsHidden( ) )
return ;

glGetIntegerv( GL_VIEWPORT, vViewport ) ;
glMatrixMode( GL_PROJECTION ) ;
glPushMatrix( ) ;
glLoadIdentity( ) ;
glOrtho( vViewport[ 0 ], vViewport[ 2 ], vViewport[ 3 ], vViewport[ 1 ], 0.0f, 1.0f ) ;
glMatrixMode( GL_MODELVIEW ) ;
glPushMatrix( ) ;
glLoadIdentity( ) ;
glDisable( GL_DEPTH_TEST ) ;
glEnable( GL_SCISSOR_TEST ) ;
glScissor( m_lX, vViewport[ 3 ] - ( ( uint )m_lY + m_uSizeY ), m_uSizeX, m_uSizeY ) ;

OnPaint( ) ;

glLoadIdentity( ) ;
glTranslatef( m_lX, m_lY, 0 ) ;

pChild = m_pChild ;
while ( NULL != pChild )
{
if ( false == pChild->IsHidden( ) )
{
glScissor( m_lX + pChild->m_lX, vViewport[ 3 ] - ( m_lY + pChild->m_lY + pChild->m_uSizeY ), pChild->m_uSizeX, pChild->m_uSizeY ) ;
pChild->OnPaint( ) ;
}

pChild = pChild->m_pChainNext ;
}

glDisable( GL_SCISSOR_TEST ) ;
glEnable( GL_DEPTH_TEST ) ;
glMatrixMode( GL_PROJECTION ) ;
glPopMatrix( ) ;
glMatrixMode( GL_MODELVIEW ) ;
glPopMatrix( ) ;
}


Like I said before, my code may not be the best and probably looks very ugly to some, but it works. So... as you can see I use some old school OpenGL but it works in a snap when I'm trying to get the functionality of my design to work.

All in all a GUI is very simple to create once you break the technology down into small peaces and concentrate work on those peaces. You text entry shouldn't be that hard. Again, my suggestions may not be the best for that, but I've used them before and they worked for me. You may want to play around or google for a better solution. Also, I used Win32 as a semi-design guide or cheat sheet. By consulting MSDN on the behavior of WM_*event-name*s. It helped me make some changes that seamed... more natural??? to work with. I didn't want my UI acting irregularly from what a use might expect.

Dude, I hope I'm not going to far by posting all this. I'm just trying to help you out. I remember very well what it was like searching on how to create a UI for a game. Finally, I believe I've gotten some where with it.
No GUIs exist for SDL 1.3 yet, at least that I know of, but there are tons available for SDL 1.2. None of them are that ideal or officially maintained by SDL developers, though.

I'm actually in the process of making a GUI for SDL 1.3. The project's hosted on sourceforge: https://sourceforge.net/projects/sdlgui/

This topic is closed to new replies.

Advertisement