TextArea GUI Element [v1.0]

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.

TextArea GUI Element [v1.0]

Postby RdR » Mon May 30, 2011 10:09 am

Hello all,

I've created a textarea class which I want to share with you if someone needs something like it.

Features:
- Multiple colors on 1 line
- Padding
- Line spacing/offset
- Adjustable size
- TextArea border ( adjustable size )
- Wrapping
- Long word chop
- Left / Right / Center aligned
- Background texture
- Multiple fonts in textarea (1 font per line)
- Image support
- (Auto) Scrolling
- Batching text to minimize draw calls
- Use RTT to improve performance
- Line lifetime (auto removed when expired )

Examples:
Image
Image

Image

Image

More examples can be found in an other project of mine TANK@WAR: http://irrlicht.sourceforge.net/phpBB2/ ... hp?t=44174

Source:
http://dev.ferket.net/irrlicht/TextArea.zip
IrrExt mirror

Example use:
cpp Code: Select all
 
// Create a new textarea
TextArea* textArea = new TextArea(Environment, Environment->getRootGUIElement());
textArea->setDimension(370, 135);
textArea->setMaxLines(6);
textArea->setAlignment(TextArea::LEFT);
textArea->setPosition(irr::core::vector2di(5, 200));
textArea->drop(); // Always drop custom GUI Elements
 
 
// Create new line
Line* line = new Line();
 
irr::core::stringw msg = L"";
msg = "Lorum ipsum";
line->addString(msg, irr::video::SColor(255, 0, 0, 0));
 
msg = "dolor";
line->addString(msg, irr::video::SColor(255, 0, 255, 0));
 
msg = "amut";
line->addString(msg, irr::video::SColor(255, 125, 255, 0));
 
// Add image to line
irr::video::ITexture* icon = Environment->getVideoDriver()->getTexture("./media/icons/icon.png");
line->addImage(icon);
 
// Add new line to chatBox
textArea->addLine(line);
 
// Create another line with different font
line = new Line(Environment->getFont("./media/fonts/arial.xml"));
 
msg = "Lorum ipsum";
line->addString(msg, irr::video::SColor(255, 0, 0, 0));
 
// Add new line to chatBox
textArea->addLine(line);
 


To use the scrolling feature make you have to get the EMIE_MOUSE_WHEEL event:

cpp Code: Select all
 
// Basic example
 
float mouseWheel;
 
bool OnEvent(const SEvent& event) {
        if (event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
                mouseWheel += event.MouseInput.Wheel;
        }
        return false;
}
 
// Put this in your handle method
if (mouseWheel > 0 || mouseWheel < 0) {
        textArea->changeStartIndex((irr::s32) mouseWheel);
}
 


Note:
Make sure you add the source of Irrlicht to your includes as well (source/Irrlicht)
Else you will get an error like: TextArea.cpp:24:22: fatal error: CGUIFont.h: No such file or directory compilation terminated.
Last edited by RdR on Tue May 15, 2012 9:42 am, edited 29 times in total.
User avatar
RdR
Competition winner
 
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm

Postby shadowslair » Mon May 30, 2011 10:53 am

Hello. I`ve made sth similar some time ago, but your looks better. Thanks for sharing. :wink:
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
User avatar
shadowslair
 
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Postby Ovan » Mon May 30, 2011 4:14 pm

Thanks for sharing :)
but i think this is not optimized, you use std::vector but why not irr::core::array ? ...
and I think this he need to PreRender the text and always update if it changed, not always update on render
User avatar
Ovan
 
Posts: 67
Joined: Thu Dec 18, 2008 12:41 am

Postby REDDemon » Tue May 31, 2011 5:13 am

Yup it can be optimized but that's not a difficult task. Good job :)
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
User avatar
REDDemon
Developer
 
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Postby RdR » Wed Jun 01, 2011 12:32 am

Ovan wrote:Thanks for sharing :)
but i think this is not optimized, you use std::vector but why not irr::core::array ? ...
and I think this he need to PreRender the text and always update if it changed, not always update on render


What do you mean by PreRender? I'm calculating the visible line only when new lines are added or the dimension of the textarea changes.

You mean something like using static text and only updating when a new line is added? (or changes in dimension)

REDDemon wrote:Yup it can be optimized but that's not a difficult task. Good job :)


Thanks, what are your suggestions for optimization?
User avatar
RdR
Competition winner
 
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm

Postby REDDemon » Wed Jun 01, 2011 7:31 am

RdR wrote:Thanks, what are your suggestions for optimization?


first of all there are some methods that can be setted as const:)

Code: Select all
irr::u32 TextArea::getNumberOfLines();
irr::core::recti getDimension();


the following methods can be added in two flavors, const and not-const. The compiler will select the best:
Code: Select all
std::vector<Line*> TextArea::getLines();


drawing method:
I personally like how do you compute all the things in the draw method. But there is also an alternative (idk if it is reallygood).

Actually you are calling all the drawings methods.
like this:

Code: Select all
for (irr::u32 i = 0; i < strings.size(); i++)
{
    irr::core::stringw str = strings.at(i); //!

    stringDimension = font->getDimension(str.c_str());
    lastDimension.LowerRightCorner.X += stringDimension.Width;

    font->draw(str.c_str(), lastDimension, colors.at(i), false, false);
    lastDimension.UpperLeftCorner.X = lastDimension.LowerRightCorner.X;
}


look at the "//!". You are just copying data, that can be copied directly to the draw() function skipping a step. The compiler can detect this redondance as not. If not you are just spending cycles re-copying data.

You can for example access data from an array when iterating, and precompute that array every time a string change

Code: Select all
font->draw(somethingelsehere, lastDimension, colors.at(i), false, false);


There are similiar things like that that can be done. I will add two test cases with original code and modified and I'll check i there is really a perfomance increase just because I want to waste some time :).
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
User avatar
REDDemon
Developer
 
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Postby hybrid » Wed Jun 01, 2011 8:16 am

Calling font->draw for single characters is also pretty cycle wasting, and will reduce render performance to a bare minimum. You have to call this method for larger portions of the text.
hybrid
Admin
 
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany

Postby REDDemon » Wed Jun 01, 2011 10:19 am

O_O I dont think he is calling it for every character, but only for whole strings.

EDIT: gotta what you mean. I don't see any easy way for doing that.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
User avatar
REDDemon
Developer
 
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Postby hybrid » Wed Jun 01, 2011 11:20 am

Check the draw2dImageBatch method. That's what is actually happening in font->draw.
hybrid
Admin
 
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany

Postby RdR » Wed Jun 01, 2011 11:29 am

hybrid wrote:Check the draw2dImageBatch method. That's what is actually happening in font->draw.


But isn't that used by all text drawing methods?
User avatar
RdR
Competition winner
 
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm

Postby REDDemon » Wed Jun 01, 2011 11:39 am

RdR wrote:
hybrid wrote:Check the draw2dImageBatch method. That's what is actually happening in font->draw.


But isn't that used by all text drawing methods?


Actually if you draw 5 different textes with the same colour they are not batched togheter with your method. so instead of 1 draw calls there will be 5 draw calls.

Every character is batched in the same text every times irrlicht call a draw font method. But you can batch more texts if you know they can be batched.

I have the feeling that the whole text on the screen can be drawed with only 1 draw call (if color is holded by vertex data). but changin the text maybe is a bit slow if it is all batched togheter. So un-batched text is not fast as light but in general is more flexible
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
User avatar
REDDemon
Developer
 
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Re: Textarea (Chatbox etc)

Postby RdR » Sun Aug 21, 2011 1:46 pm

I added some extra features:

- Multiple font support (1 font per line)
- Image support
- Scrolling

And some fixes
How to use it, see code in first post.

Source:
http://dev.ferket.net/irrlicht/TextArea.zip

Image

Image
Last edited by RdR on Wed Oct 12, 2011 10:03 am, edited 1 time in total.
User avatar
RdR
Competition winner
 
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm

Re: Textarea (Chatbox etc)

Postby Ovan » Mon Aug 22, 2011 7:28 pm

hello juste post a sample code to replace text by image

smiley varible is std::map<const char*, const char*>
cpp Code: Select all
 
void ClientEngine::initMap()
{
    smiley[":)"] = "smile.png";
    smiley[";)"] = "wink.png";
    smiley[":("] = "sad.png";
    smiley[":o"] = "surprise.png";
}
const char* ClientEngine::findFirst(irr::core::stringw text, int pos, int &find)
{
    int out = -1;
    const char *findKey = "no";
    const char *tnew = 0;
    for(std::map<const char*, const char*>::iterator i = smiley.begin(); i != smiley.end(); ++i)
    {
        int current = text.find((*i).first, pos);
        if(current > -1)
        {
            if(current < (out == -1 ? text.size() : out))
            {
                out = current;
                findKey = (*i).first;
                tnew = (*i).second;
            }
        }
    }
    printf("[%s = %s]\n", findKey, tnew);
    find = out;
    return tnew;
}
engine::addon::Line* ClientEngine::replace(engine::addon::Line *l)
{
    int pictureIndex = 0;
    engine::addon::Line *lnew = new engine::addon::Line(l->getFont());
    printf("-----------------------------------\n");
    for(int it = 0; it != l->getStrings().size(); it++)
    {
        irr::core::stringw text = l->getStrings().at(it);
        if(text == IMAGE_PLACEHOLDER)
        {
            lnew->addImage(l->getImages().at(pictureIndex));
            if(pictureIndex < l->getImages().size()) pictureIndex++;
        }
        else
        {
            int pos = 0, zln = 0;
            const char *tnew = findFirst(text, pos, zln);
            if(zln < 0) lnew->addString(text.subString(0, text.size()), l->getColors().at(it));
            while(zln != -1)
            {
                tnew = findFirst(text, pos, zln);
                lnew->addString(text.subString(pos, zln-pos), l->getColors().at(it));
                lnew->addImage(driver->getTexture(tnew));
                pos = zln+2; // smiley key size ( ":)" size = 2 )
            }
        }
    }
    delete l;
    return lnew;
}


use:
cpp Code: Select all
 
                engine::addon::Line *tmp = new engine::addon::Line();
                tmp->addString(your_text, your_color);
                history->addLine(replace(tmp));
 
User avatar
Ovan
 
Posts: 67
Joined: Thu Dec 18, 2008 12:41 am

Re: Textarea (Chatbox etc)

Postby RdR » Mon Aug 22, 2011 8:13 pm

Ovan wrote:hello juste post a sample code to replace text by image

smiley varible is std::map<const char*, const char*>
cpp Code: Select all
 
void ClientEngine::initMap()
{
    smiley[":)"] = "smile.png";
    smiley[";)"] = "wink.png";
    smiley[":("] = "sad.png";
    smiley[":o"] = "surprise.png";
}
const char* ClientEngine::findFirst(irr::core::stringw text, int pos, int &find)
{
    int out = -1;
    const char *findKey = "no";
    const char *tnew = 0;
    for(std::map<const char*, const char*>::iterator i = smiley.begin(); i != smiley.end(); ++i)
    {
        int current = text.find((*i).first, pos);
        if(current > -1)
        {
            if(current < (out == -1 ? text.size() : out))
            {
                out = current;
                findKey = (*i).first;
                tnew = (*i).second;
            }
        }
    }
    printf("[%s = %s]\n", findKey, tnew);
    find = out;
    return tnew;
}
engine::addon::Line* ClientEngine::replace(engine::addon::Line *l)
{
    int pictureIndex = 0;
    engine::addon::Line *lnew = new engine::addon::Line(l->getFont());
    printf("-----------------------------------\n");
    for(int it = 0; it != l->getStrings().size(); it++)
    {
        irr::core::stringw text = l->getStrings().at(it);
        if(text == IMAGE_PLACEHOLDER)
        {
            lnew->addImage(l->getImages().at(pictureIndex));
            if(pictureIndex < l->getImages().size()) pictureIndex++;
        }
        else
        {
            int pos = 0, zln = 0;
            const char *tnew = findFirst(text, pos, zln);
            if(zln < 0) lnew->addString(text.subString(0, text.size()), l->getColors().at(it));
            while(zln != -1)
            {
                tnew = findFirst(text, pos, zln);
                lnew->addString(text.subString(pos, zln-pos), l->getColors().at(it));
                lnew->addImage(driver->getTexture(tnew));
                pos = zln+2; // smiley key size ( ":)" size = 2 )
            }
        }
    }
    delete l;
    return lnew;
}


use:
cpp Code: Select all
 
                engine::addon::Line *tmp = new engine::addon::Line();
                tmp->addString(your_text, your_color);
                history->addLine(replace(tmp));
 


Thats a nice addon, thanks for sharing!
User avatar
RdR
Competition winner
 
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm

Re: Textarea (Chatbox etc)

Postby RdR » Mon Jan 23, 2012 3:31 pm

Updated the textarea.
Batching the text with the same font and color now, so draw() calls are minimized.
In my test project it gained from ~200 FPS to ~800 FPS :D

Image

Also fixt the wrapping for right & center alignment
And some minor bugs.

So I recommend everyone using this to upgrade to latest version.

Image
User avatar
RdR
Competition winner
 
Posts: 273
Joined: Tue Mar 29, 2011 2:58 pm

Next

Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 1 guest