balance_wheel/IrrExtensions/gui/GUIDropdownSelector.cpp

294 lines
7.4 KiB
C++

// (c) 2015 Nicolaus Anderson
// zlib license
#ifndef GUI_DROPDOWN_SELECTOR_CPP
#define GUI_DROPDOWN_SELECTOR_CPP
#include "GUIDropdownSelector.h"
#include <IGUIButton.h>
#include <IGUIContextMenu.h>
#include <IGUIEnvironment.h>
#include <IGUISpriteBank.h>
#include <IGUISkin.h>
namespace irr {
namespace gui {
using video::SColor;
GUIDropdownSelector::GUIDropdownSelector( IGUIEnvironment* pEnvironment, IGUIElement* pParent, rect<s32> pRect, s32 id )
: IGUIElement( EGUIET_ELEMENT, pEnvironment, pParent, id, pRect )
, dirty( true )
, wasMenuFocus( false )
, iconRect()
{
button = pEnvironment->addButton( rect<s32>(pRect.getSize()), this, -1, L"", L"Click to select" );
button->setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT);
button->setDrawBorder(true);
recalculateAbsolutePosition(false);
menu = pEnvironment->addContextMenu(
AbsoluteRect + core::vector2d<s32>(0, pRect.getHeight() ),
pEnvironment->getRootGUIElement()
);
menu->grab();
menu->setVisible(false);
menu->setCloseHandling( ECMC_HIDE );
menu->setEventParent(this);
s32 h = arrowHeight;
s32 hspace = (AbsoluteRect.getHeight() - h) / 2;
iconRect = rect<s32>(
AbsoluteRect.LowerRightCorner.X - (h + hspace), // upper left x
AbsoluteRect.UpperLeftCorner.Y + hspace, // upper left y
AbsoluteRect.LowerRightCorner.X - hspace, // lower right x
AbsoluteRect.LowerRightCorner.Y - hspace // lower right y
);
}
GUIDropdownSelector::~GUIDropdownSelector()
{
menu->remove(); // Removes from environment
menu->drop();
}
void GUIDropdownSelector::setText( const wchar_t* pText )
{
dirty = true;
button->setText( pText );
}
void GUIDropdownSelector::setToolTipText(const wchar_t* text)
{
button->setToolTipText(text);
}
s32 GUIDropdownSelector::getSelected() const
{
return menu->getSelectedItem();
}
const wchar_t* GUIDropdownSelector::getSelectedText() const
{
s32 i = menu->getSelectedItem();
if ( i != -1 && !dirty )
{
return menu->getItemText( i );
}
return L"";
}
const wchar_t* GUIDropdownSelector::getItemText( u32 pIndex ) const
{
return menu->getItemText( pIndex );
}
void GUIDropdownSelector::setItemText( u32 pIndex, const wchar_t* pText )
{
menu->setItemText( pIndex, pText );
}
void GUIDropdownSelector::setItemEnabled( u32 pIndex, bool pEnable )
{
menu->setItemEnabled( pIndex, pEnable );
}
bool GUIDropdownSelector::isItemEnabled( u32 pIndex ) const
{
return menu->isItemEnabled( pIndex );
}
u32 GUIDropdownSelector::getItemCount() const {
return menu->getItemCount();
}
void GUIDropdownSelector::removeItem( u32 pIndex )
{
menu->removeItem( pIndex );
}
void GUIDropdownSelector::removeAllItems()
{
menu->removeAllItems();
button->setText(L"");
}
void GUIDropdownSelector::addItem( const wchar_t* pText, bool pEnabled )
{
menu->addItem( pText, -1, pEnabled, false, false, false );
if ( menu->getItemCount() == 1 ) // first item
{
button->setText( pText );
}
}
void GUIDropdownSelector::updateAbsolutePosition()
{
IGUIElement::updateAbsolutePosition();
rect<s32> menuRect = menu->getRelativePosition();
s32 mW = menuRect.getWidth();
s32 mH = menuRect.getHeight();
/* Recall, the menu is added to the root GUI element, so its relative position is relative
to the root, and consequently at the NEW absolute position of this element. */
menu->setRelativePosition(
rect<s32>(0,0,mW,mH) + AbsoluteRect.UpperLeftCorner + core::vector2d<s32>( 0, AbsoluteRect.getHeight() )
);
s32 h = arrowHeight;
s32 hspace = (AbsoluteRect.getHeight() - h) / 2;
iconRect = rect<s32>(
AbsoluteRect.LowerRightCorner.X - (h + hspace), // upper left x
AbsoluteRect.UpperLeftCorner.Y + hspace, // upper left y
AbsoluteRect.LowerRightCorner.X - hspace, // lower right x
AbsoluteRect.LowerRightCorner.Y - hspace // lower right y
);
}
bool GUIDropdownSelector::OnEvent( const SEvent& event )
{
if ( ! isVisible() || ! isEnabled() )
return false;
if ( event.EventType != EET_GUI_EVENT )
return false;
switch ( event.GUIEvent.EventType )
{
case EGET_ELEMENT_FOCUSED:
if ( event.GUIEvent.Caller == button )
{
/* Irrlicht's CGUIEnvironment maintains the last GUI focus until the end of its setFocus() method. */
wasMenuFocus = ( Environment->getFocus() == menu );
}
break;
case EGET_BUTTON_CLICKED:
if ( event.GUIEvent.Caller == button )
{
/* Avoid opening the menu if it was already open. */
if ( ! wasMenuFocus )
{
//Parent->bringToFront(this);
menu->setVisible( true );
Environment->getRootGUIElement()->bringToFront(menu);
Environment->setFocus(menu);
return true;
}
wasMenuFocus = false;
return true;
}
break;
case EGET_MENU_ITEM_SELECTED:
if ( event.GUIEvent.Caller == menu )
{
dirty = false;
button->setText( getSelectedText() );
sendGUIEvent( EGET_COMBO_BOX_CHANGED );
return true;
}
default: break;
}
return false;
}
void GUIDropdownSelector::draw()
{
if ( ! isVisible() )
{
menu->setVisible(false); // Ensure an accidentally-opened menu is hidden
return;
}
//IGUIElement::draw();
button->draw();
menu->draw();
// Drawing a down-arrow
u32 dropDownIcon = Environment->getSkin()->getIcon( EGDI_CURSOR_DOWN /*EGDI_DROP_DOWN*/ );
//video::SColor iconColor = Environment->getSkin()->getColor( isEnabled() ? EGDC_WINDOW_SYMBOL : EGDC_GRAY_WINDOW_SYMBOL );
// if too small to draw
if ( iconRect.getWidth() < 0 || iconRect.getHeight() < 0 )
return;
Environment->getSkin()->getSpriteBank()->draw2DSprite( dropDownIcon, iconRect, &AbsoluteClippingRect );
}
void GUIDropdownSelector::sendGUIEvent( EGUI_EVENT_TYPE pEventType, IGUIElement* pElement )
{
if ( ! Parent ) return;
SEvent event;
event.EventType = EET_GUI_EVENT;
event.GUIEvent.Caller = this;
event.GUIEvent.Element = pElement;
event.GUIEvent.EventType = pEventType;
Parent->OnEvent( event );
}
void GUIDropdownSelector::serializeAttributes( io::IAttributes* out, io::SAttributeReadWriteOptions* options ) const {
IGUIElement::serializeAttributes(out, options);
out->addInt("Selected", getSelected());
out->addString("SelectedText", getSelectedText());
out->addInt("ItemCount", menu->getItemCount());
u32 i = 0;
for (; i < getItemCount(); ++i) {
core::stringc name("Item");
name += i;
name += "Text";
out->addString(name.c_str(), getItemText(i));
core::stringc label("Item");
label += i;
label += "Enabled";
out->addBool(label.c_str(), isItemEnabled(i));
}
}
void GUIDropdownSelector::deserializeAttributes( io::IAttributes* in, io::SAttributeReadWriteOptions* options ) {
IGUIElement::deserializeAttributes(in, options);
dirty = true;
u32 selected = -1;
s32 itemCount = 0;
s32 i=0;
bool enabled;
//selected = in->getAttributeAsInt("Selected", selected);
// UNAVAILABLE: IContextMenu doesn't allowing setting the Highlighted menu item.
removeAllItems();
itemCount = in->getAttributeAsInt("ItemCount", itemCount);
if ( itemCount > 0 ) {
for (; i < itemCount; ++i) {
core::stringc label("Item");
label += i;
label += "Enabled";
core::stringc name("Item");
name += i;
name += "Text";
enabled = in->getAttributeAsBool(label.c_str(), false);
addItem( in->getAttributeAsStringW(name.c_str()).c_str(), enabled );
}
}
updateAbsolutePosition();
menu->setRelativePosition(AbsoluteRect + core::vector2d<s32>(0, RelativeRect.getHeight() ));
wasMenuFocus = ( Environment->getFocus() == menu );
if ( wasMenuFocus )
Environment->setFocus(0);
}
}}
#endif // #ifndef GUI_DROPDOWN_SELECTOR_CPP