diff --git a/src/ee.h b/src/ee.h index fd2ec960c..3d9121a6b 100755 --- a/src/ee.h +++ b/src/ee.h @@ -160,5 +160,6 @@ #include "ui/cuiscrollbar.hpp" #include "ui/cuiprogressbar.hpp" #include "ui/cuilistbox.hpp" + #include "ui/cuilistboxitem.hpp" using namespace EE::UI; #endif diff --git a/src/test/ee.cpp b/src/test/ee.cpp index ca6c30bfb..ae742c360 100644 --- a/src/test/ee.cpp +++ b/src/test/ee.cpp @@ -549,14 +549,20 @@ void cEETest::CreateUI() { LBParams.Parent( C ); LBParams.PosSet( 325, 8 ); LBParams.Size = eeSize( 200, 240-16 ); - LBParams.Flags = UI_CLIP_ENABLE | UI_MULTI_SELECT | UI_AUTO_PADDING; + LBParams.Flags = UI_CLIP_ENABLE | UI_AUTO_PADDING; // | UI_MULTI_SELECT LBParams.FontSelectedColor = eeColorA( 255, 255, 255, 255 ); mListBox = eeNew( cUIListBox, ( LBParams ) ); mListBox->Visible( true ); mListBox->Enabled( true ); - for ( Int32 i = 1; i <= 12; i++ ) - mListBox->AddListBoxItem( L"Test ListBox " + toWStr(i) + L" testing it right now!" ); + Int32 wsize = 100; + + std::vector wstr(wsize); + + for ( Int32 i = 1; i <= wsize; i++ ) + wstr[i-1] = L"Test ListBox " + toWStr(i) + L" testing it right now!"; + + mListBox->AddListBoxItems( wstr ); mBuda = L"El mono ve el pez en el agua y sufre. Piensa que su mundo es el único que existe, el mejor, el real. Sufre porque es bueno y tiene compasión, lo ve y piensa: \"Pobre se está ahogando no puede respirar\". Y lo saca, lo saca y se queda tranquilo, por fin lo salvé. Pero el pez se retuerce de dolor y muere. Por eso te mostré el sueño, es imposible meter el mar en tu cabeza, que es un balde."; TTFB->ShrinkText( mBuda, 400 ); diff --git a/src/ui/cuicontrol.cpp b/src/ui/cuicontrol.cpp index c3a20a3ec..3b24b5192 100644 --- a/src/ui/cuicontrol.cpp +++ b/src/ui/cuicontrol.cpp @@ -13,7 +13,9 @@ cUIControl::cUIControl( const CreateParams& Params ) : mType( 0 ), mData( 0 ), mChild( NULL ), + mChildLast( NULL ), mNext( NULL ), + mPrev( NULL ), mBackground( Params.Background ), mBorder( Params.Border ), mControlFlags( 0 ), @@ -103,10 +105,7 @@ Uint32 cUIControl::OnMessage( const cUIMessage * Msg ) { } bool cUIControl::IsInside( const eeVector2i& Pos ) const { - if ( Pos.x >= 0 && Pos.y >= 0 && Pos.x < mSize.Width() && Pos.y < mSize.Height() ) - return true; - - return false; + return ( Pos.x >= 0 && Pos.y >= 0 && Pos.x < mSize.Width() && Pos.y < mSize.Height() ); } void cUIControl::Pos( const eeVector2i& Pos ) { @@ -221,7 +220,7 @@ void cUIControl::Update() { while ( NULL != ChildLoop ) { ChildLoop->Update(); - ChildLoop = ChildLoop->NextGet(); + ChildLoop = ChildLoop->mNext; } } @@ -301,6 +300,8 @@ Uint32 cUIControl::OnMouseExit( const eeVector2i& Pos, const Uint32 Flags ) { } Uint32 cUIControl::OnFocus() { + mControlFlags |= UI_CTRL_FLAG_HAS_FOCUS; + SendCommonEvent( cUIEvent::EventOnFocus ); SetSkinState( cUISkinState::StateFocus ); @@ -309,19 +310,19 @@ Uint32 cUIControl::OnFocus() { } Uint32 cUIControl::OnFocusLoss() { + mControlFlags &= ~UI_CTRL_FLAG_HAS_FOCUS; + SendCommonEvent( cUIEvent::EventOnFocusLoss ); return 1; } - Uint32 cUIControl::OnValueChange() { SendCommonEvent( cUIEvent::EventOnValueChange ); return 1; } - Uint32 cUIControl::HAlign() const { return mFlags & UI_HALIGN_MASK; } @@ -356,9 +357,13 @@ cUIControl * cUIControl::NextGet() const { return mNext; } +cUIControl * cUIControl::PrevGet() const { + return mPrev; +} + cUIControl * cUIControl::NextGetLoop() const { if ( NULL == mNext ) - return Parent()->ChildAt( 0 ); + return Parent()->ChildGetFirst(); else return mNext; } @@ -371,26 +376,6 @@ const Uint32& cUIControl::Data() const { return mData; } -cUIControl * cUIControl::ChildGetAt( eeVector2i CtrlPos, eeUint RecursiveLevel ) { - cUIControl * Ctrl = NULL; - - for( cUIControl * pLoop = mChild; NULL != pLoop && NULL == Ctrl; pLoop = pLoop->NextGet() ) - { - if ( !pLoop->Visible() ) - continue; - - if ( pLoop->Rect().Contains( CtrlPos ) ) { - if ( RecursiveLevel ) - Ctrl = ChildGetAt( CtrlPos - pLoop->Pos(), RecursiveLevel - 1 ); - - if ( NULL == Ctrl ) - Ctrl = pLoop; - } - } - - return Ctrl; -} - const Uint32& cUIControl::Flags() const { return mFlags; } @@ -475,20 +460,21 @@ const Uint32& cUIControl::ControlFlags() const { } void cUIControl::CheckClose() { + if ( mControlFlags & UI_CTRL_FLAG_DISABLE_CHECK_CLOSE_CHILDS ) + return; + cUIControl * ChildLoop = mChild; while( NULL != ChildLoop ) { - if ( ChildLoop->ControlFlags() & UI_CTRL_FLAG_CLOSE ) { + if ( ChildLoop->mControlFlags & UI_CTRL_FLAG_CLOSE ) { eeDelete( ChildLoop ); ChildLoop = mChild; - - continue; } ChildLoop->CheckClose(); - ChildLoop = ChildLoop->NextGet(); + ChildLoop = ChildLoop->mNext; } } @@ -512,11 +498,11 @@ void cUIControl::DrawChilds() { cUIControl * ChildLoop = mChild; while ( NULL != ChildLoop ) { - if ( ChildLoop->Visible() ) { + if ( ChildLoop->mVisible ) { ChildLoop->InternalDraw(); } - ChildLoop = ChildLoop->NextGet(); + ChildLoop = ChildLoop->mNext; } } @@ -564,15 +550,22 @@ void cUIControl::ChildDeleteAll() { } void cUIControl::ChildAdd( cUIControl * ChildCtrl ) { - if ( NULL == mChild ) - mChild = ChildCtrl; - else { + if ( NULL == mChild ) { + mChild = ChildCtrl; + mChildLast = ChildCtrl; + } else { + /* cUIControl * ChildLoop = mChild; - while ( NULL != ChildLoop->NextGet() ) - ChildLoop = ChildLoop->NextGet(); + while ( NULL != ChildLoop->mNext ) + ChildLoop = ChildLoop->mNext; ChildLoop->mNext = ChildCtrl; + */ + + mChildLast->mNext = ChildCtrl; + ChildCtrl->mPrev = mChildLast; + mChildLast = ChildCtrl; } } @@ -580,12 +573,16 @@ void cUIControl::ChildAddAt( cUIControl * ChildCtrl, Uint32 Pos ) { cUIControl * ChildLoop = mChild; if( Pos == 0 ) { - if( mChild == NULL) { - mChild = ChildCtrl; - ChildCtrl->mNext = NULL; + if ( mChild == NULL ) { + mChild = ChildCtrl; + mChildLast = ChildCtrl; + ChildCtrl->mNext = NULL; + ChildCtrl->mPrev = NULL; } else { - ChildCtrl->mNext = mChild; - mChild = ChildCtrl; + mChild->mPrev = ChildCtrl; + ChildCtrl->mNext = mChild; + ChildCtrl->mPrev = NULL; + mChild = ChildCtrl; } } else { Uint32 i = 0; @@ -596,15 +593,22 @@ void cUIControl::ChildAddAt( cUIControl * ChildCtrl, Uint32 Pos ) { } cUIControl * ChildTmp = ChildLoop->mNext; - ChildLoop->mNext = ChildCtrl; - ChildCtrl->mNext = ChildTmp; + ChildLoop->mNext = ChildCtrl; + ChildCtrl->mPrev = ChildLoop; + + ChildCtrl->mNext = ChildTmp; + ChildTmp->mPrev = ChildCtrl; } } void cUIControl::ChildRemove( cUIControl * ChildCtrl ) { - if ( ChildCtrl == mChild ) - mChild = mChild->mNext; - else { + if ( ChildCtrl == mChild ) { + mChild = mChild->mNext; + + if ( NULL != mChild ) + mChild->mPrev = NULL; + } else { + /* cUIControl * ChildLoop = mChild; while ( NULL != ChildLoop->mNext ) { @@ -615,6 +619,15 @@ void cUIControl::ChildRemove( cUIControl * ChildCtrl ) { ChildLoop = ChildLoop->mNext; } + */ + + if ( mChildLast == ChildCtrl ) + mChildLast = mChildLast->mPrev; + + ChildCtrl->mPrev->mNext = ChildCtrl->mNext; + + if ( NULL != ChildCtrl->mNext ) + ChildCtrl->mNext->mPrev = ChildCtrl->mPrev; } } @@ -646,7 +659,7 @@ Uint32 cUIControl::ChildCount() const { cUIControl * cUIControl::ChildAt( Uint32 Index ) const { cUIControl * ChildLoop = mChild; - while( NULL != ChildLoop && Index) { + while( NULL != ChildLoop && Index ) { ChildLoop = ChildLoop->mNext; Index--; } @@ -655,6 +668,7 @@ cUIControl * cUIControl::ChildAt( Uint32 Index ) const { } cUIControl * cUIControl::ChildPrev( cUIControl * Ctrl, bool Loop ) const { + /* cUIControl * ChildLoop = NULL; if ( NULL != mChild ) { @@ -662,37 +676,44 @@ cUIControl * cUIControl::ChildPrev( cUIControl * Ctrl, bool Loop ) const { ChildLoop = mChild; while ( NULL != ChildLoop ) { - if ( ChildLoop->NextGet() == Ctrl ) + if ( ChildLoop->mNext == Ctrl ) break; - ChildLoop = ChildLoop->NextGet(); + ChildLoop = ChildLoop->mNext; } } else if ( Loop ) { ChildLoop = mChild; - while ( NULL != ChildLoop->NextGet() ) - ChildLoop = ChildLoop->NextGet(); + while ( NULL != ChildLoop->mNext ) + ChildLoop = ChildLoop->mNext; } } return ChildLoop; + */ + + if ( Loop && Ctrl == mChild && NULL != mChild->mNext ) + return mChildLast; + + return Ctrl->mPrev; } cUIControl * cUIControl::ChildNext( cUIControl * Ctrl, bool Loop ) const { - cUIControl * Return = Ctrl->NextGet(); + if ( NULL == Ctrl->mNext && Loop ) + return mChild; - if ( NULL == Return && Loop ) { - Return = mChild; - } - - return Return; + return Ctrl->mNext; } cUIControl * cUIControl::ChildGetFirst() const { return mChild; } +cUIControl * cUIControl::ChildGetLast() const { + return mChildLast; +} + cUIControl * cUIControl::OverFind( const eeVector2f& Point ) { cUIControl * pOver = NULL; @@ -700,6 +721,7 @@ cUIControl * cUIControl::OverFind( const eeVector2f& Point ) { UpdateQuad(); if ( PointInsidePolygon2( mPoly, Point ) ) { + /* cUIControl * ChildLoop = mChild; while ( NULL != ChildLoop ) { @@ -710,6 +732,21 @@ cUIControl * cUIControl::OverFind( const eeVector2f& Point ) { ChildLoop = ChildLoop->mNext; } + */ + + cUIControl * ChildLoop = mChildLast; + + while ( NULL != ChildLoop ) { + cUIControl * ChildOver = ChildLoop->OverFind( Point ); + + if ( NULL != ChildOver ) { + pOver = ChildOver; + + break; // Search from top to bottom, so the first over will be the topmost + } + + ChildLoop = ChildLoop->mPrev; + } if ( NULL == pOver ) pOver = const_cast( reinterpret_cast( this ) ); @@ -719,6 +756,26 @@ cUIControl * cUIControl::OverFind( const eeVector2f& Point ) { return pOver; } +cUIControl * cUIControl::ChildGetAt( eeVector2i CtrlPos, eeUint RecursiveLevel ) { + cUIControl * Ctrl = NULL; + + for( cUIControl * pLoop = mChild; NULL != pLoop && NULL == Ctrl; pLoop = pLoop->mNext ) + { + if ( !pLoop->Visible() ) + continue; + + if ( pLoop->Rect().Contains( CtrlPos ) ) { + if ( RecursiveLevel ) + Ctrl = ChildGetAt( CtrlPos - pLoop->Pos(), RecursiveLevel - 1 ); + + if ( NULL == Ctrl ) + Ctrl = pLoop; + } + } + + return Ctrl; +} + Uint32 cUIControl::IsAnimated() { return mControlFlags & UI_CTRL_FLAG_ANIM; } @@ -939,4 +996,9 @@ eeRecti cUIControl::MakePadding( bool PadLeft, bool PadRight, bool PadTop, bool return tPadding; } +void cUIControl::DisableChildCloseCheck() { + if ( !( mControlFlags & UI_CTRL_FLAG_DISABLE_CHECK_CLOSE_CHILDS ) ) + mControlFlags |= UI_CTRL_FLAG_DISABLE_CHECK_CLOSE_CHILDS; +} + }} diff --git a/src/ui/cuicontrol.hpp b/src/ui/cuicontrol.hpp index 23cbb7a71..d8514f10c 100644 --- a/src/ui/cuicontrol.hpp +++ b/src/ui/cuicontrol.hpp @@ -168,6 +168,8 @@ class EE_API cUIControl { cUIControl * NextGet() const; + cUIControl * PrevGet() const; + cUIControl * NextGetLoop() const; void Data( const Uint32& data ); @@ -218,6 +220,8 @@ class EE_API cUIControl { cUIControl * ChildGetFirst() const; + cUIControl * ChildGetLast() const; + bool IsMouseOver(); const eePolygon2f& GetPolygon() const; @@ -225,7 +229,11 @@ class EE_API cUIControl { const eeVector2f& GetPolygonCenter() const; void SetSkinState( const Uint32& State ); + + void DisableChildCloseCheck(); protected: + friend class cUIListBoxContainer; + bool mVisible; bool mEnabled; eeVector2i mPos; @@ -236,8 +244,10 @@ class EE_API cUIControl { Uint32 mType; Uint32 mData; - cUIControl * mChild; // Pointer to the first child of the control - cUIControl * mNext; // Pointer to the next child + cUIControl * mChild; //! Pointer to the first child of the control + cUIControl * mChildLast; //! Pointer to the last child added + cUIControl * mNext; //! Pointer to the next child of the father + cUIControl * mPrev; //! Pointer to the prev child of the father cUIBackground mBackground; cUIBorder mBorder; @@ -270,7 +280,7 @@ class EE_API cUIControl { void CheckClose(); - virtual void InternalDraw(); + void InternalDraw(); void ChildDeleteAll(); @@ -290,7 +300,7 @@ class EE_API cUIControl { cUIControl * ChildNext( cUIControl * Ctrl, bool Loop = false ) const; - cUIControl * OverFind( const eeVector2f& Point ); + virtual cUIControl * OverFind( const eeVector2f& Point ); virtual void UpdateQuad(); @@ -304,7 +314,7 @@ class EE_API cUIControl { void ClipTo(); - void DrawChilds(); + virtual void DrawChilds(); eeFloat Elapsed(); diff --git a/src/ui/cuilistbox.cpp b/src/ui/cuilistbox.cpp index 1dd9b13cd..7b4770e0a 100644 --- a/src/ui/cuilistbox.cpp +++ b/src/ui/cuilistbox.cpp @@ -7,7 +7,7 @@ cUIListBox::cUIListBox( cUIListBox::CreateParams& Params ) : cUIControlAnim( Params ), mRowHeight( Params.RowHeight ), mScrollAlwaysVisible( Params.ScrollAlwaysVisible ), - mSoftScroll( Params.SoftScroll ), + mSmoothScroll( Params.SmoothScroll ), mPaddingContainer( Params.PaddingContainer ), mContainer( NULL ), mScrollBar( NULL ), @@ -21,7 +21,10 @@ cUIListBox::cUIListBox( cUIListBox::CreateParams& Params ) : mMaxTextWidth(0), mAllowHorizontalScroll( Params.AllowHorizontalScroll ), mHScrollInit(0), - mItemsNotVisible(0) + mItemsNotVisible(0), + mLastTickMove(0), + mVisibleFirst(0), + mVisibleLast(0) { mType |= UI_TYPE_LISTBOX; @@ -30,7 +33,7 @@ cUIListBox::cUIListBox( cUIListBox::CreateParams& Params ) : CParams.PosSet( mPaddingContainer.Left, mPaddingContainer.Top ); CParams.Size = eeSize( mSize.Width() - mPaddingContainer.Right - mPaddingContainer.Left, mSize.Height() - mPaddingContainer.Top - mPaddingContainer.Bottom ); CParams.Flags = Params.Flags; - mContainer = eeNew( cUIControl, ( CParams ) ); + mContainer = eeNew( cUIListBoxContainer, ( CParams ) ); mContainer->Visible( true ); mContainer->Enabled( true ); @@ -131,10 +134,10 @@ Uint32 cUIListBox::AddListBoxItem( const std::string& Text ) { Uint32 cUIListBox::AddListBoxItem( const std::wstring& Text ) { cUITextBox::CreateParams TextParams; TextParams.Parent( mContainer ); - TextParams.Flags = UI_VALIGN_CENTER | UI_HALIGN_LEFT; - TextParams.Font = mFont; - TextParams.FontColor = mFontColor; - cUIListBoxItem * tItem = eeNew( cUIListBoxItem, ( TextParams ) ); + TextParams.Flags = UI_VALIGN_CENTER | UI_HALIGN_LEFT; + TextParams.Font = mFont; + TextParams.FontColor = mFontColor; + cUIListBoxItem * tItem = eeNew( cUIListBoxItem, ( TextParams ) ); tItem->Text( Text ); return AddListBoxItem( tItem ); @@ -177,7 +180,7 @@ void cUIListBox::RemoveListBoxItems( std::vector ItemsIndex ) { if ( !erase ) { ItemsCpy.push_back( mItems[i] ); } else { - mItems[i]->Close(); + eeDelete( mItems[i] ); // doesn't call to mItems[i]->Close(); because is not checking for close. } } @@ -276,7 +279,7 @@ void cUIListBox::FindMaxWidth() { mMaxTextWidth = 0; for ( Uint32 i = 0; i < size; i++ ) { - width = mItems[i]->GetTextCache().GetTextWidth(); + width = mItems[i]->GetTextWidth(); if ( width > (Int32)mMaxTextWidth ) mMaxTextWidth = (Uint32)width; @@ -292,7 +295,7 @@ void cUIListBox::UpdateListBoxItemsSize() { } void cUIListBox::ItemUpdateSize( cUIListBoxItem * Item ) { - Int32 width = Item->GetTextCache().GetTextWidth(); + Int32 width = Item->GetTextWidth(); if ( width > (Int32)mMaxTextWidth ) mMaxTextWidth = (Uint32)width; @@ -324,9 +327,8 @@ void cUIListBox::UpdateScroll( bool FromScrollChange ) { return; cUIListBoxItem * Item; - Uint32 i, RelPos = 0; - Int32 ItemPos; - + Uint32 i, RelPos = 0, RelPosMax; + Int32 ItemPos, ItemPosMax; Int32 tHLastScroll = mHScrollInit; Uint32 VisibleItems = mContainer->Size().Height() / mRowHeight; @@ -383,9 +385,11 @@ void cUIListBox::UpdateScroll( bool FromScrollChange ) { Uint32 Scrolleable = mItems.size() * mRowHeight - mContainer->Size().Height(); bool isScrollVisible = mScrollBar->Visible(); bool isHScrollVisible = mHScrollBar->Visible(); + bool FirstVisible = false; - if ( Clipped && mSoftScroll ) { - RelPos = (Uint32)( mScrollBar->Value() * Scrolleable ); + if ( Clipped && mSmoothScroll ) { + RelPos = (Uint32)( mScrollBar->Value() * Scrolleable ); + RelPosMax = RelPos + mContainer->Size().Height() + mRowHeight; if ( ( FromScrollChange && 0xFFFFFFFF != mLastPos && mLastPos == RelPos ) && ( tHLastScroll == mHScrollInit ) ) return; @@ -395,11 +399,19 @@ void cUIListBox::UpdateScroll( bool FromScrollChange ) { for ( i = 0; i < mItems.size(); i++ ) { Item = mItems[i]; ItemPos = mRowHeight * i; + ItemPosMax = ItemPos + mRowHeight; - if ( ItemPos >= (Int32)RelPos || ItemPos + mRowHeight >= RelPos ) { + if ( ( ItemPos >= (Int32)RelPos || ItemPosMax >= (Int32)RelPos ) && ( ItemPos <= (Int32)RelPosMax ) ) { Item->Pos( mHScrollInit, ItemPos - RelPos ); Item->Enabled( true ); Item->Visible( true ); + + if ( !FirstVisible ) { + mVisibleFirst = i; + FirstVisible = true; + } + + mVisibleLast = i; } else { Item->Enabled( false ); Item->Visible( false ); @@ -409,7 +421,7 @@ void cUIListBox::UpdateScroll( bool FromScrollChange ) { ItemUpdateSize( Item ); } } else { - Uint32 RelPosMax = mItems.size(); + RelPosMax = mItems.size(); if ( mItemsNotVisible > 0 ) { RelPos = (Uint32)( mScrollBar->Value() * mItemsNotVisible ); @@ -433,6 +445,13 @@ void cUIListBox::UpdateScroll( bool FromScrollChange ) { Item->Enabled( true ); Item->Visible( true ); + + if ( !FirstVisible ) { + mVisibleFirst = i; + FirstVisible = true; + } + + mVisibleLast = i; } else { Item->Enabled( false ); Item->Visible( false ); @@ -563,16 +582,16 @@ const eeRecti& cUIListBox::PaddingContainer() const { return mPaddingContainer; } -void cUIListBox::SoftScroll( const bool& soft ) { - if ( soft != mSoftScroll ) { - mSoftScroll = soft; +void cUIListBox::SmoothScroll( const bool& soft ) { + if ( soft != mSmoothScroll ) { + mSmoothScroll = soft; UpdateScroll(); } } -const bool& cUIListBox::SoftScroll() const { - return mSoftScroll; +const bool& cUIListBox::SmoothScroll() const { + return mSmoothScroll; } void cUIListBox::ScrollAlwaysVisible( const bool& visible ) { @@ -617,4 +636,76 @@ Uint32 cUIListBox::Size() { return mItems.size(); } +void cUIListBox::ManageKeyboard() { + if ( !mSelected.size() || mFlags & UI_MULTI_SELECT ) + return; + + cInput * KM = cUIManager::instance()->GetInput(); + Int32 SelIndex = 0; + + if ( eeGetTicks() - mLastTickMove > 100 ) { + if ( KM->IsKeyDown( KEY_DOWN ) ) { + mLastTickMove = eeGetTicks(); + + SelIndex = mSelected.front() + 1; + + if ( SelIndex < (Int32)mItems.size() ) { + mItems[ mSelected.front() ]->Unselect(); + + if ( ScrollBar()->Visible() ) { + if ( mItems[ SelIndex ]->Pos().y + (Int32)RowHeight() > mContainer->Size().Height() ) { + ScrollBar()->Value( (eeFloat)( SelIndex * mRowHeight ) / (eeFloat)( ( mItems.size() - 1 ) * mRowHeight ) ); + + cUIManager::instance()->FocusControl( mItems[ SelIndex ] ); + } + } + + mItems[ SelIndex ]->Select(); + } + } else if ( KM->IsKeyDown( KEY_UP ) ) { + mLastTickMove = eeGetTicks(); + + SelIndex = mSelected.front() - 1; + + if ( SelIndex >= 0 ) { + mItems[ mSelected.front() ]->Unselect(); + + if ( ScrollBar()->Visible() ) { + if ( mItems[ SelIndex ]->Pos().y < 0 ) { + ScrollBar()->Value( (eeFloat)( SelIndex * mRowHeight ) / (eeFloat)( ( mItems.size() - 1 ) * mRowHeight ) ); + + cUIManager::instance()->FocusControl( mItems[ SelIndex ] ); + } + } + + mItems[ mSelected.front() - 1 ]->Select(); + } + } else if ( KM->IsKeyDown( KEY_PAGEUP ) ) { + mLastTickMove = eeGetTicks(); + + if ( mSelected.front() != 0 ) { + mItems[ mSelected.front() ]->Unselect(); + + ScrollBar()->Value( 0 ); + + cUIManager::instance()->FocusControl( mItems[ 0 ] ); + + mItems[ 0 ]->Select(); + } + } else if ( KM->IsKeyDown( KEY_PAGEDOWN ) ) { + mLastTickMove = eeGetTicks(); + + if ( mSelected.front() != Size() - 1 ) { + mItems[ mSelected.front() ]->Unselect(); + + ScrollBar()->Value( 1 ); + + cUIManager::instance()->FocusControl( mItems[ Size() - 1 ] ); + + mItems[ Size() - 1 ]->Select(); + } + } + } +} + }} diff --git a/src/ui/cuilistbox.hpp b/src/ui/cuilistbox.hpp index c245958b1..6d94d4c5f 100644 --- a/src/ui/cuilistbox.hpp +++ b/src/ui/cuilistbox.hpp @@ -4,6 +4,7 @@ #include "cuicontrolanim.hpp" #include "cuiscrollbar.hpp" #include "cuilistboxitem.hpp" +#include "cuilistboxcontainer.hpp" namespace EE { namespace UI { @@ -15,7 +16,7 @@ class EE_API cUIListBox : public cUIControlAnim { cUIControl::CreateParams(), RowHeight( 0 ), ScrollAlwaysVisible( false ), - SoftScroll( true ), + SmoothScroll( true ), AllowHorizontalScroll( true ), PaddingContainer(), Font( NULL ), @@ -29,7 +30,7 @@ class EE_API cUIListBox : public cUIControlAnim { Uint32 RowHeight; bool ScrollAlwaysVisible; - bool SoftScroll; + bool SmoothScroll; bool AllowHorizontalScroll; eeRecti PaddingContainer; cFont * Font; @@ -98,9 +99,9 @@ class EE_API cUIListBox : public cUIControlAnim { const eeRecti& PaddingContainer() const; - void SoftScroll( const bool& soft ); + void SmoothScroll( const bool& soft ); - const bool& SoftScroll() const; + const bool& SmoothScroll() const; void ScrollAlwaysVisible( const bool& visible ); @@ -117,12 +118,13 @@ class EE_API cUIListBox : public cUIControlAnim { Uint32 Size(); protected: friend class cUIListBoxItem; + friend class cUIListBoxContainer; Uint32 mRowHeight; bool mScrollAlwaysVisible; - bool mSoftScroll; + bool mSmoothScroll; eeRecti mPaddingContainer; - cUIControl * mContainer; + cUIListBoxContainer * mContainer; cUIScrollBar * mScrollBar; cUIScrollBar * mHScrollBar; cFont * mFont; @@ -135,6 +137,11 @@ class EE_API cUIListBox : public cUIControlAnim { bool mAllowHorizontalScroll; Int32 mHScrollInit; Int32 mItemsNotVisible; + Uint32 mLastTickMove; + + Uint32 mVisibleFirst; + Uint32 mVisibleLast; + std::list mSelected; std::vector mItems; @@ -167,6 +174,8 @@ class EE_API cUIListBox : public cUIControlAnim { void AutoPadding(); void FindMaxWidth(); + + void ManageKeyboard(); }; }} diff --git a/src/ui/cuilistboxcontainer.cpp b/src/ui/cuilistboxcontainer.cpp new file mode 100644 index 000000000..40636ae26 --- /dev/null +++ b/src/ui/cuilistboxcontainer.cpp @@ -0,0 +1,62 @@ +#include "cuilistboxcontainer.hpp" +#include "cuilistbox.hpp" +#include "cuilistboxitem.hpp" + +namespace EE { namespace UI { + +cUIListBoxContainer::cUIListBoxContainer( cUIControl::CreateParams& Params ) : + cUIControl( Params ) +{ + DisableChildCloseCheck(); +} + +cUIListBoxContainer::~cUIListBoxContainer() +{ +} + +void cUIListBoxContainer::Update() { + cUIListBox * LBParent = reinterpret_cast ( Parent() ); + + if ( LBParent->mItems.size() ) { + for ( Uint32 i = LBParent->mVisibleFirst; i <= LBParent->mVisibleLast; i++ ) + LBParent->mItems[i]->Update(); + } +} + +void cUIListBoxContainer::DrawChilds() { + cUIListBox * LBParent = reinterpret_cast ( Parent() ); + + if ( LBParent->mItems.size() ) { + for ( Uint32 i = LBParent->mVisibleFirst; i <= LBParent->mVisibleLast; i++ ) + LBParent->mItems[i]->InternalDraw(); + } +} + +cUIControl * cUIListBoxContainer::OverFind( const eeVector2f& Point ) { + cUIListBox * LBParent = reinterpret_cast ( Parent() ); + + cUIControl * pOver = NULL; + + if ( mVisible && mEnabled && LBParent->mItems.size() ) { + UpdateQuad(); + + if ( PointInsidePolygon2( mPoly, Point ) ) { + for ( Uint32 i = LBParent->mVisibleFirst; i <= LBParent->mVisibleLast; i++ ) { + cUIControl * ChildOver = LBParent->mItems[i]->OverFind( Point ); + + if ( NULL != ChildOver ) { + pOver = ChildOver; + + break; + } + } + + if ( NULL == pOver ) + pOver = const_cast( reinterpret_cast( this ) ); + } + } + + return pOver; +} + +}} diff --git a/src/ui/cuilistboxcontainer.hpp b/src/ui/cuilistboxcontainer.hpp new file mode 100644 index 000000000..d7ac7b877 --- /dev/null +++ b/src/ui/cuilistboxcontainer.hpp @@ -0,0 +1,23 @@ +#ifndef EE_UICUILISTBOXCONTAINER_HPP +#define EE_UICUILISTBOXCONTAINER_HPP + +#include "cuicontrol.hpp" + +namespace EE { namespace UI { + +class cUIListBoxContainer : public cUIControl { + public: + cUIListBoxContainer( cUIControl::CreateParams& Params ); + + ~cUIListBoxContainer(); + + void Update(); + + void DrawChilds(); + + cUIControl * OverFind( const eeVector2f& Point ); +}; + +}} + +#endif diff --git a/src/ui/cuilistboxitem.cpp b/src/ui/cuilistboxitem.cpp index 5088b0a11..449d005bd 100644 --- a/src/ui/cuilistboxitem.cpp +++ b/src/ui/cuilistboxitem.cpp @@ -5,8 +5,7 @@ namespace EE { namespace UI { cUIListBoxItem::cUIListBoxItem( cUITextBox::CreateParams& Params ) : - cUITextBox( Params ), - mSelected( false ) + cUITextBox( Params ) { mType |= UI_TYPE_LISTBOXITEM; @@ -22,70 +21,81 @@ void cUIListBoxItem::SetTheme( cUITheme * Theme ) { } Uint32 cUIListBoxItem::OnMouseClick( const eeVector2i& Pos, const Uint32 Flags ) { - cUIListBox * LBParent = reinterpret_cast ( Parent()->Parent() ); - if ( Flags & EE_BUTTONS_LRM ) { - bool wasSelected = mSelected; - - LBParent->ItemClicked( this ); - - if ( LBParent->IsMultiSelect() ) { - if ( !wasSelected ) { - SetSkinState( cUISkinState::StateSelected ); - - mSelected = true; - - LBParent->mSelected.push_back( LBParent->GetItemIndex( this ) ); - - LBParent->OnSelected(); - } else { - mSelected = false; - - LBParent->mSelected.remove( LBParent->GetItemIndex( this ) ); - } - } else { - SetSkinState( cUISkinState::StateSelected ); - - mSelected = true; - - LBParent->mSelected.clear(); - LBParent->mSelected.push_back( LBParent->GetItemIndex( this ) ); - LBParent->OnSelected(); - } + Select(); } return 1; } -void cUIListBoxItem::Update() { - if ( mEnabled && mVisible && IsMouseOver() ) { - Uint32 Flags = cUIManager::instance()->GetInput()->ClickTrigger(); +void cUIListBoxItem::Select() { + cUIListBox * LBParent = reinterpret_cast ( Parent()->Parent() ); - if ( Flags & EE_BUTTONS_WUWD ) { - cUIListBox * LBParent = reinterpret_cast ( Parent()->Parent() ); + bool wasSelected = mControlFlags & UI_CTRL_FLAG_SELECTED; - LBParent->ScrollBar()->Slider()->ManageClick( Flags ); + LBParent->ItemClicked( this ); + + if ( LBParent->IsMultiSelect() ) { + if ( !wasSelected ) { + SetSkinState( cUISkinState::StateSelected ); + + mControlFlags |= UI_CTRL_FLAG_SELECTED; + + LBParent->mSelected.push_back( LBParent->GetItemIndex( this ) ); + + LBParent->OnSelected(); + } else { + mControlFlags &= ~UI_CTRL_FLAG_SELECTED; + + LBParent->mSelected.remove( LBParent->GetItemIndex( this ) ); + } + } else { + SetSkinState( cUISkinState::StateSelected ); + + mControlFlags |= UI_CTRL_FLAG_SELECTED; + + LBParent->mSelected.clear(); + LBParent->mSelected.push_back( LBParent->GetItemIndex( this ) ); + + if ( !wasSelected ) { + LBParent->OnSelected(); } } } -Uint32 cUIListBoxItem::OnMouseExit( const eeVector2i& Pos, const Uint32 Flags ) { - cUITextBox::OnMouseExit( Pos, Flags ); +void cUIListBoxItem::Update() { + if ( mEnabled && mVisible ) { + cUIListBox * LBParent = reinterpret_cast ( Parent()->Parent() ); + Uint32 Flags = cUIManager::instance()->GetInput()->ClickTrigger(); - if ( mSelected ) + if ( IsMouseOver() ) { + if ( Flags & EE_BUTTONS_WUWD ) + LBParent->ScrollBar()->Slider()->ManageClick( Flags ); + } + + if ( ( mControlFlags & UI_CTRL_FLAG_HAS_FOCUS ) ) + LBParent->ManageKeyboard(); + } +} + +Uint32 cUIListBoxItem::OnMouseExit( const eeVector2i& Pos, const Uint32 Flags ) { + cUIControl::OnMouseExit( Pos, Flags ); + + if ( mControlFlags & UI_CTRL_FLAG_SELECTED ) SetSkinState( cUISkinState::StateSelected ); return 1; } void cUIListBoxItem::Unselect() { - mSelected = false; + if ( mControlFlags & UI_CTRL_FLAG_SELECTED ) + mControlFlags &= ~UI_CTRL_FLAG_SELECTED; SetSkinState( cUISkinState::StateNormal ); } -const bool& cUIListBoxItem::Selected() const { - return mSelected; +bool cUIListBoxItem::Selected() const { + return mControlFlags & UI_CTRL_FLAG_SELECTED; } void cUIListBoxItem::OnStateChange() { diff --git a/src/ui/cuilistboxitem.hpp b/src/ui/cuilistboxitem.hpp index 243d705e7..b74dc1c0c 100644 --- a/src/ui/cuilistboxitem.hpp +++ b/src/ui/cuilistboxitem.hpp @@ -19,12 +19,12 @@ class EE_API cUIListBoxItem : public cUITextBox { virtual void Update(); - const bool& Selected() const; + bool Selected() const; void Unselect(); - protected: - bool mSelected; + void Select(); + protected: virtual void OnStateChange(); }; diff --git a/src/ui/cuitextbox.cpp b/src/ui/cuitextbox.cpp index bb4729a16..b961e9487 100644 --- a/src/ui/cuitextbox.cpp +++ b/src/ui/cuitextbox.cpp @@ -174,4 +174,16 @@ cTextCache& cUITextBox::GetTextCache() { return mTextCache; } +eeFloat cUITextBox::GetTextWidth() { + return mTextCache.GetTextWidth(); +} + +eeFloat cUITextBox::GetTextHeight() { + return mTextCache.GetTextHeight(); +} + +const eeInt& cUITextBox::GetNumLines() const { + return mTextCache.GetNumLines(); +} + }} diff --git a/src/ui/cuitextbox.hpp b/src/ui/cuitextbox.hpp index ed849b67e..b40d72f59 100644 --- a/src/ui/cuitextbox.hpp +++ b/src/ui/cuitextbox.hpp @@ -61,6 +61,12 @@ class EE_API cUITextBox : public cUIControlAnim { virtual void SetTheme( cUITheme * Theme ); cTextCache& GetTextCache(); + + eeFloat GetTextWidth(); + + eeFloat GetTextHeight(); + + const eeInt& GetNumLines() const; protected: cTextCache mTextCache; eeColorA mFontColor; diff --git a/src/ui/cuitextboxsimple.cpp b/src/ui/cuitextboxsimple.cpp new file mode 100644 index 000000000..7bc12547b --- /dev/null +++ b/src/ui/cuitextboxsimple.cpp @@ -0,0 +1,200 @@ +#include "cuitextboxsimple.hpp" +#include "cuimanager.hpp" +#include "cuithememanager.hpp" + +namespace EE { namespace UI { + +cUITextBoxSimple::cUITextBoxSimple( const cUITextBox::CreateParams& Params ) : + cUIControl( Params ), + mFont( NULL ), + mCachedWidth( NULL ), + mNumLines( 1 ), + mFontColor( Params.FontColor ), + mFontShadowColor( Params.FontShadowColor ), + mAlignOffset( 0.f, 0.f ) +{ + mType |= UI_TYPE_GET(UI_TYPE_TEXTBOX); + + mFont = Params.Font; + + if ( NULL == Params.Font && NULL != cUIThemeManager::instance()->DefaultFont() ) { + mFont = cUIThemeManager::instance()->DefaultFont(); + } else { + eePRINT( "cUITextBoxSimple::cUITextBoxSimple : Created a UI TextBox without a defined font." ); + } + + AutoAlign(); +} + +cUITextBoxSimple::~cUITextBoxSimple() { +} + +void cUITextBoxSimple::Draw() { + if ( mVisible ) { + cUIControl::Draw(); + + if ( mCachedWidth ) { + if ( mFlags & UI_CLIP_ENABLE ) + cUIManager::instance()->ClipEnable( mScreenPos.x + mPadding.Left, mScreenPos.y + mPadding.Top, mSize.Width() - mPadding.Left - mPadding.Right, mSize.Height() - mPadding.Bottom ); + + eeColorA OldColor = mFont->Color(); + eeColorA OldShadowColor = mFont->ShadowColor(); + + mFont->Color( mFontColor ); + mFont->ShadowColor( mFontShadowColor ); + + mFont->Draw( mText, (eeFloat)mScreenPos.x + mAlignOffset.x + (eeFloat)mPadding.Left + 1.f, (eeFloat)mScreenPos.y + mAlignOffset.y + (eeFloat)mPadding.Top, Flags(), 1.f, 0.f, mBlend ); + + mFont->Color( OldColor ); + mFont->ShadowColor( OldShadowColor ); + + if ( mFlags & UI_CLIP_ENABLE ) + cUIManager::instance()->ClipDisable(); + } + } +} + +cFont * cUITextBoxSimple::Font() const { + return mFont; +} + +void cUITextBoxSimple::Font( cFont * font ) { + mFont = font; + AutoShrink(); + AutoSize(); + AutoAlign(); + OnFontChanged(); +} + +const std::wstring& cUITextBoxSimple::Text() { + return mText; +} + +void cUITextBoxSimple::Text( const std::string& text ) { + Text( stringTowstring( text ) ); +} + +void cUITextBoxSimple::Text( const std::wstring& text ) { + mText = text; + + if ( NULL != mFont && mText.size() ) { + std::vector LinesWidth; + + mFont->CacheWidth( mText, LinesWidth, mCachedWidth, mNumLines ); + }else { + mCachedWidth = 0; + } + + AutoShrink(); + AutoSize(); + AutoAlign(); + OnTextChanged(); +} + +const eeColorA& cUITextBoxSimple::Color() const { + return mFontColor; +} + +void cUITextBoxSimple::Color( const eeColorA& color ) { + mFontColor = color; + Alpha( color.A() ); +} + +const eeColorA& cUITextBoxSimple::ShadowColor() const { + return mFontShadowColor; +} + +void cUITextBoxSimple::ShadowColor( const eeColorA& color ) { + mFontShadowColor = color; + Alpha( color.A() ); +} + +void cUITextBoxSimple::Alpha( const eeFloat& alpha ) { + mFontColor.Alpha = (Uint8)alpha; + mFontShadowColor.Alpha = (Uint8)alpha; +} + +void cUITextBoxSimple::AutoShrink() { + if ( Flags() & UI_AUTO_SHRINK_TEXT ) { + mFont->ShrinkText( mText, mSize.Width() ); + } +} + +void cUITextBoxSimple::AutoSize() { + if ( Flags() & UI_AUTO_SIZE ) { + mSize.Width( mCachedWidth ); + mSize.Height( (eeFloat)mFont->GetFontSize() * (eeFloat)mNumLines ); + } +} + +void cUITextBoxSimple::AutoAlign() { + switch ( FontHAlignGet( Flags() ) ) { + case UI_HALIGN_CENTER: + mAlignOffset.x = (eeFloat)( (Int32)( mSize.x - mCachedWidth ) / 2 ); + break; + case UI_HALIGN_RIGHT: + mAlignOffset.x = ( (eeFloat)mSize.x - (eeFloat)mCachedWidth ); + break; + case UI_HALIGN_LEFT: + mAlignOffset.x = 0.f; + break; + } + + switch ( FontVAlignGet( Flags() ) ) { + case UI_VALIGN_CENTER: + mAlignOffset.y = (eeFloat)( ( (Int32)( mSize.y - GetTextHeight() ) ) / 2 ); + break; + case UI_VALIGN_BOTTOM: + mAlignOffset.y = ( (eeFloat)mSize.y - GetTextHeight() ); + break; + case UI_VALIGN_TOP: + mAlignOffset.y = 0.f; + break; + } +} + +void cUITextBoxSimple::OnSizeChange() { + AutoShrink(); + AutoSize(); + AutoAlign(); + + cUIControl::OnSizeChange(); +} + +void cUITextBoxSimple::OnTextChanged() { + SendCommonEvent( cUIEvent::EventOnTextChanged ); +} + +void cUITextBoxSimple::OnFontChanged() { + SendCommonEvent( cUIEvent::EventOnFontChanged ); +} + +void cUITextBoxSimple::Padding( const eeRecti& padding ) { + mPadding = padding; +} + +const eeRecti& cUITextBoxSimple::Padding() const { + return mPadding; +} + +void cUITextBoxSimple::SetTheme( cUITheme * Theme ) { + cUIControl::SetTheme( Theme ); + + if ( NULL == mFont && NULL != Theme->DefaultFont() ) { + mFont = Theme->DefaultFont(); + } +} + +eeFloat cUITextBoxSimple::GetTextWidth() { + return mCachedWidth; +} + +eeFloat cUITextBoxSimple::GetTextHeight() { + return ( (eeFloat)mFont->GetFontSize() * (eeFloat)mNumLines ); +} + +const eeInt& cUITextBoxSimple::GetNumLines() const { + return mNumLines; +} + +}} diff --git a/src/ui/cuitextboxsimple.hpp b/src/ui/cuitextboxsimple.hpp new file mode 100644 index 000000000..773c79525 --- /dev/null +++ b/src/ui/cuitextboxsimple.hpp @@ -0,0 +1,74 @@ +#ifndef EE_UICUITEXTBOXSIMPLE_H +#define EE_UICUITEXTBOXSIMPLE_H + +#include "cuicontrol.hpp" +#include "cuitextbox.hpp" + +namespace EE { namespace UI { + +class EE_API cUITextBoxSimple : public cUIControl { + public: + cUITextBoxSimple( const cUITextBox::CreateParams& Params ); + + ~cUITextBoxSimple(); + + virtual void Draw(); + + virtual void Alpha( const eeFloat& alpha ); + + cFont * Font() const; + + void Font( cFont * font ); + + virtual const std::wstring& Text(); + + virtual void Text( const std::wstring& text ); + + virtual void Text( const std::string& text ); + + const eeColorA& Color() const; + + void Color( const eeColorA& color ); + + const eeColorA& ShadowColor() const; + + void ShadowColor( const eeColorA& color ); + + virtual void OnTextChanged(); + + virtual void OnFontChanged(); + + virtual void Padding( const eeRecti& padding ); + + const eeRecti& Padding() const; + + virtual void SetTheme( cUITheme * Theme ); + + eeFloat GetTextWidth(); + + eeFloat GetTextHeight(); + + const eeInt& GetNumLines() const; + protected: + std::wstring mText; + cFont * mFont; + eeFloat mCachedWidth; + eeInt mNumLines; + + eeColorA mFontColor; + eeColorA mFontShadowColor; + eeVector2f mAlignOffset; + eeRecti mPadding; + + virtual void OnSizeChange(); + + void AutoShrink(); + + void AutoSize(); + + void AutoAlign(); +}; + +}} + +#endif diff --git a/src/ui/uihelper.hpp b/src/ui/uihelper.hpp index bb220d8ab..8cbda2124 100644 --- a/src/ui/uihelper.hpp +++ b/src/ui/uihelper.hpp @@ -19,17 +19,26 @@ Uint32 EE_API HAlignGet( Uint32 Flags ); Uint32 EE_API VAlignGet( Uint32 Flags ); -#define UI_CTRL_FLAG_CLOSE_POS (0) -#define UI_CTRL_FLAG_CLOSE (1 << UI_CTRL_FLAG_CLOSE_POS) +#define UI_CTRL_FLAG_CLOSE_POS (0) +#define UI_CTRL_FLAG_CLOSE (1 << UI_CTRL_FLAG_CLOSE_POS) -#define UI_CTRL_FLAG_CLOSE_FO_POS (1) -#define UI_CTRL_FLAG_CLOSE_FO (1 << UI_CTRL_FLAG_CLOSE_FO_POS) +#define UI_CTRL_FLAG_CLOSE_FO_POS (1) +#define UI_CTRL_FLAG_CLOSE_FO (1 << UI_CTRL_FLAG_CLOSE_FO_POS) -#define UI_CTRL_FLAG_ANIM_POS (2) -#define UI_CTRL_FLAG_ANIM (1 << UI_CTRL_FLAG_ANIM_POS) +#define UI_CTRL_FLAG_ANIM_POS (2) +#define UI_CTRL_FLAG_ANIM (1 << UI_CTRL_FLAG_ANIM_POS) -#define UI_CTRL_FLAG_MOUSEOVER_POS (3) -#define UI_CTRL_FLAG_MOUSEOVER (1 << UI_CTRL_FLAG_MOUSEOVER_POS) +#define UI_CTRL_FLAG_MOUSEOVER_POS (3) +#define UI_CTRL_FLAG_MOUSEOVER (1 << UI_CTRL_FLAG_MOUSEOVER_POS) + +#define UI_CTRL_FLAG_HAS_FOCUS_POS (4) +#define UI_CTRL_FLAG_HAS_FOCUS (1 << UI_CTRL_FLAG_HAS_FOCUS_POS) + +#define UI_CTRL_FLAG_SELECTED_POS (5) +#define UI_CTRL_FLAG_SELECTED (1 << UI_CTRL_FLAG_SELECTED_POS) + +#define UI_CTRL_FLAG_DISABLE_CHECK_CLOSE_CHILDS_POS (6) +#define UI_CTRL_FLAG_DISABLE_CHECK_CLOSE_CHILDS (1 << UI_CTRL_FLAG_DISABLE_CHECK_CLOSE_CHILDS_POS) #define UI_TEXT_DRAW_SHADOW FONT_DRAW_SHADOW #define UI_AUTO_SIZE (1 << 6) @@ -58,7 +67,7 @@ Uint32 EE_API VAlignGet( Uint32 Flags ); #define UI_TYPE_LISTBOX (12) #define UI_TYPE_LISTBOXITEM (13) -#define UI_TYPE_GET(X) ( 1 << (X) ) +#define UI_TYPE_GET(X) ( 1 << (X) ) }}