From 1d6a992ee001c86d52d5e550520e2aedfa6be5f6 Mon Sep 17 00:00:00 2001 From: bitplane Date: Wed, 18 Jul 2007 22:47:05 +0000 Subject: [PATCH] fixed bugs with listbox automatic visibility of scrollbars, and clicking on listbox scrollbars when in a combo box. items in a listbox are now selected as you type their text. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@799 dfc29bdd-3216-0410-991c-e03cc46cb475 --- changes.txt | 10 +-- source/Irrlicht/CGUIComboBox.cpp | 23 +++++- source/Irrlicht/CGUIListBox.cpp | 119 ++++++++++++++++++++++++------- source/Irrlicht/CGUIListBox.h | 3 + 4 files changed, 124 insertions(+), 31 deletions(-) diff --git a/changes.txt b/changes.txt index c4b9c686..2dc676bb 100644 --- a/changes.txt +++ b/changes.txt @@ -66,7 +66,7 @@ GUI: - EGET_ELEMENT_FOCUS_LOST and EGET_ELEMENT_FOCUSED events can now be absorbed by returning true in OnEvent. Absorbing these events will cancel the focus - change. + change. - IGUIEnvironment::setFocus and removeFocus now return bools. @@ -124,9 +124,11 @@ GUI: - IGUIStaticText new methods setDrawBorder and setTextAlignment. - - Added IGUIListBox::setAutoScrollEnabled and isAutoScrollEnabled, for automatic - scrolling when selecting or adding an item. Scrollbars are now only visible - when the list doesn't fit in the visible area. + - IGUIListBox changes: + Added setAutoScrollEnabled and isAutoScrollEnabled, for automatic scrolling + when selecting or adding an item. + Scrollbars are now only visible when the list doesn't fit in the visible area. + You can now type an item's text to select it. Changes in version 1.3.1 (20 Jun 2007) diff --git a/source/Irrlicht/CGUIComboBox.cpp b/source/Irrlicht/CGUIComboBox.cpp index 1f30f97e..d6d8d57e 100644 --- a/source/Irrlicht/CGUIComboBox.cpp +++ b/source/Irrlicht/CGUIComboBox.cpp @@ -199,7 +199,7 @@ bool CGUIComboBox::OnEvent(SEvent event) if (Selected <0) Selected = 0; - else + if (Selected >= (s32)Items.size()) Selected = (s32)Items.size() -1; @@ -216,9 +216,12 @@ bool CGUIComboBox::OnEvent(SEvent event) switch(event.GUIEvent.EventType) { case EGET_ELEMENT_FOCUS_LOST: - if (Environment->hasFocus(ListBox) && + if (ListBox && + (Environment->hasFocus(ListBox) || ListBox->isMyChild(event.GUIEvent.Caller) ) && event.GUIEvent.Element != this && - event.GUIEvent.Element != ListButton) + event.GUIEvent.Element != ListButton && + event.GUIEvent.Element != ListBox && + !ListBox->isMyChild(event.GUIEvent.Element)) { openCloseMenu(); } @@ -279,6 +282,20 @@ bool CGUIComboBox::OnEvent(SEvent event) } } break; + case EMIE_MOUSE_WHEEL: + { + s32 oldSelected = Selected; + Selected += (event.MouseInput.Wheel < 0) ? 1 : -1; + + if (Selected <0) + Selected = 0; + + if (Selected >= (s32)Items.size()) + Selected = (s32)Items.size() -1; + + if (Selected != oldSelected) + sendSelectionChangedEvent(); + } } break; } diff --git a/source/Irrlicht/CGUIListBox.cpp b/source/Irrlicht/CGUIListBox.cpp index 99372e62..f48e2f02 100644 --- a/source/Irrlicht/CGUIListBox.cpp +++ b/source/Irrlicht/CGUIListBox.cpp @@ -23,7 +23,8 @@ CGUIListBox::CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, : IGUIListBox(environment, parent, id, rectangle), Selected(-1), ItemHeight(0), TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0), ScrollBar(0), Selecting(false), DrawBack(drawBack), - MoveOverSelect(moveOverSelect), selectTime(0), AutoScroll(true) + MoveOverSelect(moveOverSelect), selectTime(0), AutoScroll(true), + KeyBuffer(), LastKeyTime(0), HighlightWhenNotFocused(true) { #ifdef _DEBUG setDebugName("CGUIListBox"); @@ -170,7 +171,7 @@ void CGUIListBox::recalculateItemHeight() TotalItemHeight = ItemHeight * Items.size(); ScrollBar->setMax(TotalItemHeight - AbsoluteRect.getHeight()); - if( TotalItemHeight < AbsoluteRect.getHeight() ) + if( TotalItemHeight <= AbsoluteRect.getHeight() ) ScrollBar->setVisible(false); else ScrollBar->setVisible(true); @@ -276,6 +277,85 @@ bool CGUIListBox::OnEvent(SEvent event) } return true; } + else if (event.KeyInput.PressedDown && event.KeyInput.Char) + { + // change selection based on text as it is typed. + u32 now = os::Timer::getTime(); + + if (now - LastKeyTime < 500) + { + // add to key buffer if it isn't a key repeat + if (!(KeyBuffer.size() == 1 && KeyBuffer[0] == event.KeyInput.Char)) + { + KeyBuffer += L" "; + KeyBuffer[KeyBuffer.size()-1] = event.KeyInput.Char; + } + } + else + { + KeyBuffer = L" "; + KeyBuffer[0] = event.KeyInput.Char; + } + LastKeyTime = now; + + // find the selected item, starting at the current selection + s32 start = Selected; + s32 current = start+1; + // dont change selection if the key buffer matches the current item + if (Selected > -1 && KeyBuffer.size() > 1) + { + if (Items[Selected].text.size() >= KeyBuffer.size() && + KeyBuffer.equals_ignore_case(Items[Selected].text.subString(0,KeyBuffer.size()))) + return true; + } + + while (current < (s32)Items.size()) + { + if (Items[current].text.size() >= KeyBuffer.size()) + { + if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size()))) + { + if (Parent && Selected != current && !Selecting && !MoveOverSelect) + { + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_LISTBOX_CHANGED; + Parent->OnEvent(e); + } + setSelected(current); + return true; + } + } + current++; + } + current = 0; + while (current <= start) + { + if (Items[current].text.size() >= KeyBuffer.size()) + { + if (KeyBuffer.equals_ignore_case(Items[current].text.subString(0,KeyBuffer.size()))) + { + if (Parent && Selected != current && !Selecting && !MoveOverSelect) + { + Selected = current; + SEvent e; + e.EventType = EET_GUI_EVENT; + e.GUIEvent.Caller = this; + e.GUIEvent.Element = 0; + e.GUIEvent.EventType = EGET_LISTBOX_CHANGED; + Parent->OnEvent(e); + } + setSelected(current); + return true; + } + } + current++; + } + + return true; + } break; case EET_GUI_EVENT: @@ -306,26 +386,11 @@ bool CGUIListBox::OnEvent(SEvent event) case EMIE_LMOUSE_PRESSED_DOWN: { - IGUIElement *el = Environment->getRootGUIElement()->getElementFromPoint( - core::position2di(event.MouseInput.X, event.MouseInput.Y)); - - if (Environment->hasFocus(this) && - ScrollBar == el && - ScrollBar->OnEvent(event)) - { - return true; - } - Selecting = true; - Environment->setFocus(this); return true; } case EMIE_LMOUSE_LEFT_UP: - if (Environment->hasFocus(this) && - ScrollBar->isPointInside(p) && - ScrollBar->OnEvent(event)) - return true; if (!isPointInside(p)) { @@ -372,8 +437,9 @@ void CGUIListBox::selectNew(s32 ypos, bool onlyHover) if (Selected<0) Selected = 0; - // post the news + recalculateScrollPos(); + // post the news if (Parent && !onlyHover) { SEvent event; @@ -413,7 +479,8 @@ void CGUIListBox::draw() core::rect clientClip(AbsoluteRect); clientClip.UpperLeftCorner.Y += 1; clientClip.UpperLeftCorner.X += 1; - clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); + if (ScrollBar->isVisible()) + clientClip.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); clientClip.LowerRightCorner.Y -= 1; clientClip.clipAgainst(AbsoluteClippingRect); @@ -425,18 +492,22 @@ void CGUIListBox::draw() frameRect = AbsoluteRect; frameRect.UpperLeftCorner.X += 1; - frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); + if (ScrollBar->isVisible()) + frameRect.LowerRightCorner.X = AbsoluteRect.LowerRightCorner.X - skin->getSize(EGDS_SCROLLBAR_SIZE); + frameRect.LowerRightCorner.Y = AbsoluteRect.UpperLeftCorner.Y + ItemHeight; frameRect.UpperLeftCorner.Y -= ScrollBar->getPos(); frameRect.LowerRightCorner.Y -= ScrollBar->getPos(); + bool hl = (HighlightWhenNotFocused || Environment->hasFocus(this) || Environment->hasFocus(ScrollBar)); + for (s32 i=0; i<(s32)Items.size(); ++i) { if (frameRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y && frameRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y) { - if (i == Selected) + if (i == Selected && hl) skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), frameRect, &clientClip); core::rect textRect = frameRect; @@ -450,13 +521,13 @@ void CGUIListBox::draw() iconPos.Y += textRect.getHeight() / 2; iconPos.X += ItemsIconWidth/2; IconBank->draw2DSprite( (u32)Items[i].icon, iconPos, &clientClip, - skin->getColor((i==Selected) ? EGDC_ICON_HIGH_LIGHT : EGDC_ICON), - (i==Selected) ? selectTime : 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true); + skin->getColor((i==Selected && hl) ? EGDC_ICON_HIGH_LIGHT : EGDC_ICON), + (i==Selected && hl) ? selectTime : 0 , (i==Selected) ? os::Timer::getTime() : 0, false, true); } textRect.UpperLeftCorner.X += ItemsIconWidth+3; - Font->draw(Items[i].text.c_str(), textRect, skin->getColor((i==Selected) ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT), false, true, &clientClip); + Font->draw(Items[i].text.c_str(), textRect, skin->getColor((i==Selected && hl) ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT), false, true, &clientClip); textRect.UpperLeftCorner.X -= ItemsIconWidth+3; } diff --git a/source/Irrlicht/CGUIListBox.h b/source/Irrlicht/CGUIListBox.h index e6d9e9c6..4657eef0 100644 --- a/source/Irrlicht/CGUIListBox.h +++ b/source/Irrlicht/CGUIListBox.h @@ -113,6 +113,9 @@ namespace gui bool MoveOverSelect; u32 selectTime; bool AutoScroll; + core::stringw KeyBuffer; + u32 LastKeyTime; + bool HighlightWhenNotFocused; };