Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: cpGUI - A new object oriented GUI toolkit based on SFML 1.5  (Read 55348 times)

0 Members and 1 Guest are viewing this topic.

forrestcupp

  • Jr. Member
  • **
  • Posts: 57
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« on: August 07, 2009, 07:46:26 pm »
I was working on some GUI stuff to use in my SFML projects, and it ended up turning into a decent object oriented GUI toolkit.  It's object oriented, and extremely easy to use.  

I figured it might be useful to people, so I'm going to release it under the zlib/libpng license like SFML.  It is called cpGUI, and it's based on SFML version 1.5.

It includes the following controls:
* Normal highlightable Buttons with a text label
* Image Buttons that are based on an sf::Image
* Shape Buttons that take an sf::Shape and turn it into a clickable button
* Check Boxes
* Selection Boxes with the ability to add choices.  It uses a scroll bar when necessary
* Drop Down Boxes with the ability to add choices and set maximum depth. A scroll bar is used when you reach your maximum depth.
* Text Input Boxes - a one line box for inputting text.  It has a blinking caret, but it is non-editable
* Text Boxes for loading a simple text file and displaying it.  The Text Box will automatically word wrap the text according to the size of the box you create.  This is useful for displaying instructions or licensing info. Text Boxes are non-editable and read only.
* A GuiContainer class that contains all of your objects - used for setting focus, and also some other things under the hood.

Almost all of the work is done for you, and it is very simple to use.  In most of the controls, you can easily customize the colors, fonts, size, & position.  Each object can return its state and tell you if the mouse enters or exits the control, and can tell you if the button was clicked or if it's down.

If anyone is interested, I can upload it and put it in the wiki when I have time.  I'll post a screen shot that includes all of the available controls.  If I post the files in the wiki, I'll include the example code for the screen shot with lots of comments explaining how to use cpGUI.

Update:
I have added a built-in font manager to help save on resources. Now, rather than having a separate font for each object, new fonts are only loaded when necessary. Also, when a font is no longer used by any object, it is automatically deleted. Other than cpGUI's default font, you will never have an unused font in memory.

This is all automatic, and it doesn't change how cpGUI is used.

Thanks to “Meltra Bour” for pointing out the need on the forums. Thanks to “l0calh05t” & “Wavesonics” for helping me learn how to implement this.

**Major Update** - 9/28/9

See this post for details.  Includes functions for setting mouseover color, bug fixes, and separate files to include only the controls you need for your project.

**Update** - 9/29/09

See this post for details.  Update includes various tweaks, bug fixes, and now cpGUI has static libraries.


You can download the latest update in the Projects section of the Wiki.



Lokk

  • Full Member
  • ***
  • Posts: 228
    • View Profile
    • http://betadineproject.wordpress.com/
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #1 on: August 07, 2009, 09:05:38 pm »
Great job =)
Quote
If anyone is interested, I can upload it and put it in the wiki when I have time. I'll post a screen shot that includes all of the available controls. If I post the files in the wiki, I'll include the example code for the screen shot with lots of comments explaining how to use cpGUI.

Sounds good !
(Well, I am more interested in your source code... I am working on a gui here if you want to see it... )

forrestcupp

  • Jr. Member
  • **
  • Posts: 57
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #2 on: August 08, 2009, 06:44:18 pm »
Sorry to preempt you.  I guess it's always good for people to have choices.  It's also good to have different license choices, since you're using GPLv3 and I'm using zlib/libpng license.

Anyway, I got a wiki page up under the English Projects section.  You can find my wiki page here, and you can download the code from that page.  It's in a zip file.


Edit:
I've updated my code to put everything in a namespace called cp.  I also fixed a small bug with the drop down box.

Meltra Bour

  • Newbie
  • *
  • Posts: 28
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #3 on: August 09, 2009, 08:18:25 am »
Thx to both, was fun reading true the code, gui elements like those where somewhere on my todo list this puched it right up to the top. I have never been a fan of xml files so I'm glad to see the right lib with the right license. so thx for the time saver and thx for the learning xp lokk ...

I'l be integrating the code in to our little engine over the coming week so I'l keep you posted on how it works out 8)

Meltra Bour

  • Newbie
  • *
  • Posts: 28
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #4 on: August 10, 2009, 08:38:21 am »
First small steps, I'm a bit of a c++ newby but ...

The thing I was missing was a font manager, it seems you create a new instance of sf::Font for every object in the gui. It feels like this is a bit of a waist on resources, using a manager to spread one instance over several objects would speed up loading and reduce memory usage. Or is my newby mind playing trick on me ?

Auron

  • Newbie
  • *
  • Posts: 15
    • MSN Messenger - videogamefreak101@hotmail.com
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #5 on: August 10, 2009, 09:30:05 pm »
Looks nice, it will be great to see when its released.

forrestcupp

  • Jr. Member
  • **
  • Posts: 57
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #6 on: August 10, 2009, 11:53:42 pm »
Quote from: "Meltra Bour"
First small steps, I'm a bit of a c++ newby but ...

The thing I was missing was a font manager, it seems you create a new instance of sf::Font for every object in the gui. It feels like this is a bit of a waist on resources, using a manager to spread one instance over several objects would speed up loading and reduce memory usage. Or is my newby mind playing trick on me ?
I'll have to consider how to do that without losing the ability to have different fonts for different objects.  I could probably figure out a way to do it through the cpGuiContainer.

That is a good point, though.

Quote from: "Auron"
Looks nice, it will be great to see when its released.
Are you talking about mine, which was the original post, or Lokk's?  If you're talking about mine, it's in the wiki in the project section.

forrestcupp

  • Jr. Member
  • **
  • Posts: 57
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #7 on: August 11, 2009, 12:23:22 am »
I'm thinking about the font problem mentioned earlier, and here's the problem.  SFML currently doesn't properly resize fonts.  If you have a font that was loaded at a size of 12 and resize it to 20, it's still has the same pixels it had as 12 but is blown up to be the size of 20.  Because of that, it doesn't look so great sometimes.  Even starting at a high size and lowering the size leaves nasty artifacts.

So in my code, I opted for quality by actually reloading the font at the new size when the user calls the SetFontSize() function.  The thing is, people are going to at least want different font sizes for different things like text boxes, selection boxes or buttons, even if they're using the default font.  If I have a central font, and the user wants to resize one thing, they will all be resized as a result of my method of doing things for quality sake.

So it seems that every time someone wants an object with a different font size, I would have to load a different font into a font manager.  I can't really see how that would be any better on resources than each object having its own font, unless I were to reprogram the entire way that SFML works with fonts.  I'm definitely not going to do that because my wife is having a baby next week, and it's not really my job anyway to do that.

So, does anyone have any solutions of an easier way to handle this problem?  Is it a big enough problem to even open a can of worms like this?  I'm open to suggestions here.

l0calh05t

  • Full Member
  • ***
  • Posts: 200
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #8 on: August 11, 2009, 12:47:36 am »
Quote from: "forrestcupp"
So, does anyone have any solutions of an easier way to handle this problem?  Is it a big enough problem to even open a can of worms like this?  I'm open to suggestions here.


You could have a look at my resource manager ( http://www.sfml-dev.org/wiki/en/sources/resource_manager_l0calh05t ), it includes a sf::Font example. This would prevent reloading of the fonts as long as different elements use the same font size (so 8 buttons with font size 20 will share one font)

Auron

  • Newbie
  • *
  • Posts: 15
    • MSN Messenger - videogamefreak101@hotmail.com
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #9 on: August 11, 2009, 01:28:53 am »
I don't which project I was talking about, but the GUI thing looks really nice.

forrestcupp

  • Jr. Member
  • **
  • Posts: 57
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #10 on: August 11, 2009, 01:59:07 am »
Quote from: "l0calh05t"
Quote from: "forrestcupp"
So, does anyone have any solutions of an easier way to handle this problem?  Is it a big enough problem to even open a can of worms like this?  I'm open to suggestions here.


You could have a look at my resource manager ( http://www.sfml-dev.org/wiki/en/sources/resource_manager_l0calh05t ), it includes a sf::Font example. This would prevent reloading of the fonts as long as different elements use the same font size (so 8 buttons with font size 20 will share one font)
What would happen if you called ReleaseUnusedResources() from inside the event loop instead of directly after?  

I'm trying to visualize a way to incorporate something like this without the user of cpGUI even having to know about its workings.

redkiing

  • Newbie
  • *
  • Posts: 8
    • View Profile
    • http://redkiing.wordpress.com
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #11 on: August 11, 2009, 02:22:55 am »
Hi forrestcupp,
Nice work!! I think you're gui toolkit is really easy to use, and the included controls are indeed very useful.
However, I don't like that when you resize the window, the gui objects used by the toolkit don't work anymore. They keep using the old coords, so when you try clicking one button when the window has been resized, nothing happens...

I've navigated through your code and I modified the required functions to make it work.

I've create a Vect2f object called mousePos using the new coords with this little line of code in every place you verify the mouse coords:

Code: [Select]
sf::Vector2f mousePos = Parent->ConvertCoords(input->GetMouseX(), input->GetMouseY());

So, Instead of using
Code: [Select]
input->GetMouseX()
input->GetMouseY()

I use :
Code: [Select]
mousePos.x
mousePos.y

For instance, this function:
Code: [Select]
/// Checks to see if mouse pointer is inside control.  Returns true if it is.
bool cpObject::CheckMouseEntered(const sf::Input *input)
{
return (input->GetMouseX() >= PosX && input->GetMouseX() <= PosX+Width &&
input->GetMouseY() >= PosY && input->GetMouseY() <= PosY+Height);
}

translates into:
Code: [Select]
/// Checks to see if mouse pointer is inside control.  Returns true if it is.
bool cpObject::CheckMouseEntered(const sf::Input *input)
{
    sf::Vector2f mousePos = Parent->ConvertCoords(input->GetMouseX(), input->GetMouseY());
return (mousePos.x >= PosX && mousePos.x <= PosX+Width &&
        mousePos.y >= PosY && mousePos.y <= PosY+Height);
}

Hope it helps.

l0calh05t

  • Full Member
  • ***
  • Posts: 200
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #12 on: August 11, 2009, 08:39:56 am »
Quote from: "forrestcupp"
What would happen if you called ReleaseUnusedResources() from inside the event loop instead of directly after?


Shouldn't make much of a difference, as most of the time there'll only be one event waiting anyways. If there are more you'll waste a bit of processing time be rescanning the map.

Quote
I'm trying to visualize a way to incorporate something like this without the user of cpGUI even having to know about its workings.


Well, you could of course modify the resource manager to discard anything the moment it goes out of use by storing boost::weak_pointers in the map instead of boost::shared_pointers (would only require an extra check in the GetResource function, because a resource in the map doesn't have to mean it's still loaded anymore)

EDIT:

Here's an (untested) modified version:
Code: [Select]

template<typename T>
class ResourceManager {
public:
typedef boost::shared_ptr<T> Resource;
typedef boost::weak_ptr<T> WeakResource;
typedef std::map<std::string, WeakResource> ResourceMap;
 
// Gets the resource described by the locator and loads it if it hasn't been loaded yet
Resource GetResource(const std::string& locator)
{
boost::mutex::scoped_lock lock(resource_mutex);
 
Resource loaded;
ResourceMap::iterator it = resources.find(locator);
if(it == resources.end()) // not loaded yet, load now
{
loaded = LoadResource(locator);
if(loaded)
it = resources.insert(std::make_pair(locator, loaded)).first;
else
throw std::runtime_error("Resource " + locator + " could not be loaded");
}
else
{
loaded = it->second.lock();
if(!loaded)
{
loaded = LoadResource(locator);
if(loaded)
it->second = loaded;
else
throw std::runtime_error("Resource " + locator + " could not be loaded");
}
}
 
return loaded;
}
 
protected:
// must be implemented for the corresponding resource type
virtual Resource LoadResource(const std::string& locator) = 0;
 
private:
ResourceMap resources;
boost::mutex resource_mutex;
};

forrestcupp

  • Jr. Member
  • **
  • Posts: 57
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #13 on: August 11, 2009, 02:17:38 pm »
Quote from: "redkiing"
Hi forrestcupp,
Nice work!! I think you're gui toolkit is really easy to use, and the included controls are indeed very useful.
However, I don't like that when you resize the window, the gui objects used by the toolkit don't work anymore. They keep using the old coords, so when you try clicking one button when the window has been resized, nothing happens...

I've navigated through your code and I modified the required functions to make it work.
Sweet!  Thank you!

I didn't even think about that because I'm going to be mostly using full screen.  Also, I'm used to wxWidgets not automatically resizing everything for you.  I'll update it when I get a chance and get it posted.  Thanks again.

Quote from: "l0calh05t"

Well, you could of course modify the resource manager to discard anything the moment it goes out of use by storing boost::weak_pointers in the map instead of boost::shared_pointers (would only require an extra check in the GetResource function, because a resource in the map doesn't have to mean it's still loaded anymore)
I know what I'm about to ask is probably remedial.  

I have a class called cpGuiContainer that takes care of some global GUI stuff.  Do you think I could just make an std::vector of sf::Fonts in my cpGuiContainer class.  It will always have my default font, and when someone loads a new font, it will be loaded into this vector if it's not already there.  Through my GuiContainer, I can keep track of what object uses which font, and only have one instance per font/fontsize.  Then when an object changes fonts/fontsizes, at that time cpGuiContainer can load the new one if necessary, and purge the vector of any unused fonts.  That way, it only happens when the user changes a font.  If I did that, instead of having each object create an instance to a font, the objects would be using a pointer to a font that is in cpGuiContainer's vector.

If that could work, it may be a more personalized way for me to do it.  What do you think?

l0calh05t

  • Full Member
  • ***
  • Posts: 200
    • View Profile
cpGUI - A new object oriented GUI toolkit based on SFML 1.5
« Reply #14 on: August 11, 2009, 03:49:08 pm »
Quote from: "forrestcupp"
I know what I'm about to ask is probably remedial.  

I have a class called cpGuiContainer that takes care of some global GUI stuff.  Do you think I could just make an std::vector of sf::Fonts in my cpGuiContainer class.  It will always have my default font, and when someone loads a new font, it will be loaded into this vector if it's not already there.  Through my GuiContainer, I can keep track of what object uses which font, and only have one instance per font/fontsize.  Then when an object changes fonts/fontsizes, at that time cpGuiContainer can load the new one if necessary, and purge the vector of any unused fonts.  That way, it only happens when the user changes a font.  If I did that, instead of having each object create an instance to a font, the objects would be using a pointer to a font that is in cpGuiContainer's vector.

If that could work, it may be a more personalized way for me to do it.  What do you think?


Of course you could do it that way, but a vector is a bad choice for this because:

1. Searching for a specific font+size will be O(n), compared to O(log(n)) for a map
2. Removing an element that is not at the end involves copying large parts of the vector

also you'll have to do your own reference counting.

Why not use a manager like mine as a member of cpGuiContainer, and get your fonts from there? This would be invisible to the user. (It will add dependencies to boost::thread and boost::smart_ptr though... if you can get away with no thread safety, you might remove the lock/mutex and boost::smart_ptr only requires a few headers)

 

anything