Adding a scrollbar in a list box

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Adding a scrollbar in a list box

Post by wsw1231 »

I know that when there are more and more items (texts) in the list box, the scroll bar will appear.

But, if I add a large button in the list box, there will be no scroll bar.

How can I add a scrollbar in a list box and hardcode its height?
Which API should I use?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

Currently you can't force it to be there. The corresponding calculation is happening in CGUIListBox::recalculateItemHeight().
So easiest solution might be to copy that code, rename the class, change it in that copy and then add your own listbox element.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

Do you mean I should change CGUIListBox to IGUIListBox?

Code: Select all

void CGUIListBox::recalculateItemHeight()
{
	IGUISkin* skin = Environment->getSkin();

	if (Font != skin->getFont())
	{
		if (Font)
			Font->drop();

		Font = skin->getFont();
		if ( 0 == ItemHeightOverride )
			ItemHeight = 0;

		if (Font)
		{
			if ( 0 == ItemHeightOverride )
				ItemHeight = Font->getDimension(L"A").Height + 4;

			Font->grab();
		}
	}

	TotalItemHeight = ItemHeight * Items.size();
	ScrollBar->setMax(TotalItemHeight - AbsoluteRect.getHeight());
	s32 minItemHeight = ItemHeight > 0 ? ItemHeight : 1;
	ScrollBar->setSmallStep ( minItemHeight );
	ScrollBar->setLargeStep ( 2*minItemHeight );

	if ( TotalItemHeight <= AbsoluteRect.getHeight() )
		ScrollBar->setVisible(false);
	else
		ScrollBar->setVisible(true);
}
So, after I change that, where should I paste to? I cannot find IGUIListBox.cpp

Also, after pasting the code to a correct place, how can I use that API to make the scroll bar appear where the list box has a large button?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

No, I mean you make an own class out of it. Whatever the name (MyCGUIListBox for example).
And that could look identical otherwise except that ScrollBar->setVisible would always be set to true for example.

So the idea is: Create your own class (in your own project). As basis to make it easier copy over the Irrlicht-class which does already nearly everything you need (except for example different scrollbar behaviour).
Read the code, understand what it does and then add your own changes.

I must admit I don't really get what you mean with "adding a large Button to a listbox". If you want to add it _in_ the element then you have to code it in your own element. But I have no idea for what you would want a button in a listbox.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

What I mean by a large button is that
it has the size larger than the list box.

E.g. The list box has size 400x400, while the button has 30x500 which means the whole button cannot be seen and it is reasonable to see it by using a scrollbar.

So that's why I am asking how to solve that...
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

Sorry, I still don't get what a button has to do with a listbox. A listbox contains text not buttons - I just don't get the connection here. Or are you talking about clipping and the listbox is the parent of the button? Maybe tell what you are trying to do. Could be there is a better way to do it once I get what this is about.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

My idea is to create an area in which there are some buttons, once there are more and more buttons, there will be a scrollbar in that area.

I dont know if it is suitable to use a listbox as that "area"

Do you have any better idea?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

Hm, I understand. And no - using a listbox for that is probably not such a good idea. A list box is really there for text and maybe some icons.

This would be a new gui-element. I have no such element, but maybe it could be written the following way: Your gui-element would contain 2 major subElements. An IGUIStaticText (without border, without text and without background drawing - so it would be invisible) and a IGUIScrollBar. All buttons would be placed on the IGUIStaticText, so they are childs of that. Then if you move the scrollbar the position of the IGUIStatictext should be updated. You can catch the scrollbar-events in the OnEvent function of your gui-element. As the invisible statictext is clipped automatically by the parent (the element itself) you would only see buttons which are within the size of your gui-element.

This might sound a little complicated to you at first - but it's something I'm sure you can manage when you put a little work into it. You start by deriving your class from IGUIElement. You might take a look at the code of the checkboxclass in the other thread as example which also just is a new gui-element. You can also look into the listbox implementation how it's done there. And once you know how to write own gui-elements you are getting a lot more flexible in what you can do in your game.

Just ask when you get stuck - we can help you with your first gui-element :-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

OK.
You mean I should attach a scrollbar to a static text field.

But I don't know how to change the visible region of IGUIStaticText triggered by an event.

E.g. to make things simpler, press down arrow key to move the visible region downward instead of using scrollbar. Can I do this?

Could you give me some hints? :(
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

wsw1231 wrote:OK.
You mean I should attach a scrollbar to a static text field.
No, I don't mean that. I mean you should write your own gui-element and attach a statictext + a scrollbar to that. Structure would approximately like that:

Code: Select all

CMyScrollingArea : public irr::gui::IGUIElement 
{
  virtual bool OnEvent (const SEvent &event);
  irr::gui::IGUIScrollBar * myScrollBar;
  irr::gui::IGUIStaticText * myBackGround;
};
All your buttons would be added to myBackGround (which should be sufficiently large). And because myBackGround is automatically clipped to it's parent (CMyScrollingArea) all you have to do on scrolling-events is to change the position of myBackGround.

And to catch the scrolling events your CMyScrollingArea class can override OnEvent and handle the events there. If you want to use keyboard-buttons instead - they are handled very similar. Also catch the button-events in the OnEvent of CMyScrollingArea and set the position of myBackGround correspondingly.

Note that as mention in the last post you can set myBackGround to values which make it completely invisible - it is just a container to move your buttons easier. Alternatively you could work completely without that statictext and instead keep all your buttons in an array and move all button positions whenever you want to scroll. Which solution you prefer is up to you.

Just moving the buttons might even be better, so alternatively your class could look like this:

Code: Select all

CMyScrollingArea : public irr::gui::IGUIElement 
{
  virtual bool OnEvent (const SEvent &event);
  irr::gui::IGUIScrollBar * myScrollBar; 
  irr::core::array<IGUIButton*> myButtons;
};
Please try to write the code to actually move the buttons yourself.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

CuteAlien wrote:
wsw1231 wrote:OK.
You mean I should attach a scrollbar to a static text field.
No, I don't mean that. I mean you should write your own gui-element and attach a statictext + a scrollbar to that. Structure would approximately like that:

Code: Select all

CMyScrollingArea : public irr::gui::IGUIElement 
{
  virtual bool OnEvent (const SEvent &event);
  irr::gui::IGUIScrollBar * myScrollBar;
  irr::gui::IGUIStaticText * myBackGround;
};
All your buttons would be added to myBackGround (which should be sufficiently large). And because myBackGround is automatically clipped to it's parent (CMyScrollingArea) all you have to do on scrolling-events is to change the position of myBackGround.

And to catch the scrolling events your CMyScrollingArea class can override OnEvent and handle the events there. If you want to use keyboard-buttons instead - they are handled very similar. Also catch the button-events in the OnEvent of CMyScrollingArea and set the position of myBackGround correspondingly.

Note that as mention in the last post you can set myBackGround to values which make it completely invisible - it is just a container to move your buttons easier. Alternatively you could work completely without that statictext and instead keep all your buttons in an array and move all button positions whenever you want to scroll. Which solution you prefer is up to you.

Just moving the buttons might even be better, so alternatively your class could look like this:

Code: Select all

CMyScrollingArea : public irr::gui::IGUIElement 
{
  virtual bool OnEvent (const SEvent &event);
  irr::gui::IGUIScrollBar * myScrollBar; 
  irr::core::array<IGUIButton*> myButtons;
};
Please try to write the code to actually move the buttons yourself.
Thanks for your advice.

But I think the first approach may be more suitable in my case because I want to make the buttons clipped if they are outside of the "area" (i.e. IGUIStaticText)

You mention that I should change the position of the IGUIStaticText.
Do you mean

Code: Select all

IGUIStaticText * text = guienv->addStaticText(L"", 
      rect<s32>(10,10,50,50), true); 

   IGUIButton* button = guienv->addButton(rect<s32>(100,100,130,130), text, -1, L"hahaha");

   text->setRelativePosition(core::rect<s32>(20,20,140,140));
Both the positions of the IGUIStaticText and button will be changed if I use the above code.

So, which API should I use to change the position of IGUIStaticText (i.e. visible region instead of the whole rectangle) while keeping that of the button unchanged?
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

wsw1231 wrote: Both the positions of the IGUIStaticText and button will be changed if I use the above code.

So, which API should I use to change the position of IGUIStaticText (i.e. visible region instead of the whole rectangle) while keeping that of the button unchanged?
Well, you need to change both... how would you scroll buttons otherwise if they would stay on their place? If you want another button on the same place as an old button before scrolling (I think you talk about that - correct me if I guessed wrong), then move by the size of the gap between your buttons.

And clipping would work in both solutions. Because childs are clipped against your gui-element.

edit: It won't work that way without an own gui-element! Start with that.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

........
My idea is as follows:
Image
You can image that the black box is the IGUIStaticText and the red box is the button. The above picture shows that the button is outside of the IGUIStaticText, which means it is clipped.

Image
Now, what I want to do is to change the visible region of IGUIStaticText so that I can see the red box in the black box.

However, what

Code: Select all

text->setRelativePosition(core::rect<s32>(20,20,140,140)); 
does is that the whole IGUIStaticText position will change and since the button is the child of it, so it will also be changed.

This is NOT what I want.
I just want to visible region to be changed only but it seems there is no API to do so :(
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Post by CuteAlien »

As I wrote - you need an own gui-element. I can only repeat that. Then you have 2(!) areas. One (invisible) to move and one for clipping. Although you could fake it with 2 statictexts above each other as well (but that's just more work in the long run - create an own gui-element, that will get simpler, cleaner and more flexible).

You might notice that in your shot you actually moved the red marker. Which means - you moved the button into the non-clipped area (the behind a second static-text is simply that you can easy move more than one button at a time, you don't really need it as my second solution showed).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
wsw1231
Posts: 148
Joined: Fri Oct 01, 2010 7:55 am

Post by wsw1231 »

Code: Select all

CMyScrollingArea : public irr::gui::IGUIElement 
{ 
  virtual bool OnEvent (const SEvent &event); 
  irr::gui::IGUIScrollBar * myScrollBar; 
  irr::core::array<IGUIButton*> myButtons; 
}; 

Oh....Do you mean the region is defined in the IGUIElement constructor???
If so, I think I get what you mean now. :)
Post Reply