From e977420aa68b9d12a3a5883870ade58ffb4a8f49 Mon Sep 17 00:00:00 2001 From: spartanj Date: Mon, 11 Oct 2010 22:20:26 -0300 Subject: [PATCH] Added cUISpinBox control to the UI. Added events when a value in a control change ( for the slider, checkbox, ratiobutton, spinbox ). Fixed text alignment on cUITextBox. --- ee.linux.cbp | 2 + src/ee.h | 1 + src/test/ee.cpp | 88 ++++++++++---- src/ui/cuicheckbox.cpp | 2 + src/ui/cuicontrol.cpp | 8 ++ src/ui/cuicontrol.hpp | 2 + src/ui/cuievent.hpp | 1 + src/ui/cuiradiobutton.cpp | 10 +- src/ui/cuislider.cpp | 2 + src/ui/cuispinbox.cpp | 204 ++++++++++++++++++++++++++++++++ src/ui/cuispinbox.hpp | 74 ++++++++++++ src/ui/cuitextbox.cpp | 6 +- src/ui/cuitextbox.hpp | 6 +- src/ui/cuitextinput.cpp | 21 +++- src/ui/cuitextinput.hpp | 18 ++- src/ui/uihelper.hpp | 3 +- src/utils/string.cpp | 5 +- src/utils/string.hpp | 2 +- src/window/cinputtextbuffer.cpp | 70 +++++++++-- src/window/cinputtextbuffer.hpp | 29 +++-- 20 files changed, 495 insertions(+), 59 deletions(-) create mode 100644 src/ui/cuispinbox.cpp create mode 100644 src/ui/cuispinbox.hpp diff --git a/ee.linux.cbp b/ee.linux.cbp index fd85919b9..b5c13f916 100644 --- a/ee.linux.cbp +++ b/ee.linux.cbp @@ -538,6 +538,8 @@ + + diff --git a/src/ee.h b/src/ee.h index 78afad2a1..b8cb0d8ea 100755 --- a/src/ee.h +++ b/src/ee.h @@ -156,5 +156,6 @@ #include "ui/cuicheckbox.hpp" #include "ui/cuiradiobutton.hpp" #include "ui/cuislider.hpp" + #include "ui/cuispinbox.hpp" using namespace EE::UI; #endif diff --git a/src/test/ee.cpp b/src/test/ee.cpp index a228eac25..94ec9869c 100644 --- a/src/test/ee.cpp +++ b/src/test/ee.cpp @@ -194,8 +194,22 @@ class cEETest : private cThread { cVertexBuffer * mVBO; void ButtonClick( const cUIEvent * Event ); + void CreateAquaTextureAtlas(); }; +void cEETest::CreateAquaTextureAtlas() { + std::string Path( MyPath + "data/aqua" ); + + if ( !FileExists( Path + ".etg" ) ) { + cTexturePacker tp( 512, 512, true, 2 ); + tp.AddTexturesPath( Path ); + tp.PackTextures(); + tp.Save( Path + ".png", EE_SAVE_TYPE_PNG ); + } else { + cTextureGroupLoader tgl; + tgl.UpdateTextureAtlas( Path + ".etg", Path ); + } +} void cEETest::Init() { EE = cEngine::instance(); @@ -223,6 +237,8 @@ void cEETest::Init() { MyPath = AppPath(); + CreateAquaTextureAtlas(); + cIniFile Ini( MyPath + "data/ee.ini" ); Ini.ReadFile(); @@ -413,7 +429,6 @@ void cEETest::CreateUI() { InputParams.Size = eeSize( 300, 22 ); InputParams.Flags = UI_VALIGN_CENTER | UI_HALIGN_LEFT | UI_CLIP_ENABLE; // | UI_BORDER | UI_FILL_BACKGROUND InputParams.Font = TTF; - InputParams.SupportNewLine = false; cUITextInput * Input = eeNew( cUITextInput, ( InputParams ) ); Input->Padding( eeRectf( 4, -2, -8, 0 ) ); Input->Visible( true ); @@ -426,6 +441,7 @@ void cEETest::CreateUI() { Button->Visible( true ); Button->Enabled( true ); Button->Text( L"Click Me" ); + Button->Padding( eeRectf( 0, -1, 0, 0 ) ); Button->AddEventListener( cUIEvent::EventMouseClick, cb::Make1( this, &cEETest::ButtonClick ) ); TextParams.PosSet( 120, 20 ); @@ -462,10 +478,34 @@ void cEETest::CreateUI() { mSlider->Visible( true ); mSlider->Enabled( true ); + cUISpinBox::CreateParams SpinBoxParams; + SpinBoxParams.Parent( C ); + SpinBoxParams.PosSet( 80, 150 ); + SpinBoxParams.Size = eeSize( 80, 23 ); + SpinBoxParams.Flags = UI_VALIGN_CENTER | UI_HALIGN_LEFT | UI_CLIP_ENABLE; // | UI_BORDER | UI_FILL_BACKGROUND + SpinBoxParams.Font = TTF; + SpinBoxParams.AllowDotsInNumbers = true; + cUISpinBox * mSpinBox = eeNew( cUISpinBox, ( SpinBoxParams ) ); + mSpinBox->Visible( true ); + mSpinBox->Enabled( true ); + mSpinBox->Padding( eeRectf( 2, 0, -2, 0 ) ); + 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.\nPowered by Text Shrinker =)"; TTF->ShrinkText( mBuda, 400 ); /** Replace this with the texture atlas and an auto theme loader */ + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_normal_ml.png" ), "aqua_button_normal_ml" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_normal_mr.png" ), "aqua_button_normal_mr" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_normal_m.png" ), "aqua_button_normal_m" ) ) ); + + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_menter_ml.png" ), "aqua_button_menter_ml" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_menter_mr.png" ), "aqua_button_menter_mr" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_menter_m.png" ), "aqua_button_menter_m" ) ) ); + + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_mdown_ml.png" ), "aqua_button_mdown_ml" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_mdown_mr.png" ), "aqua_button_mdown_mr" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_button_mdown_m.png" ), "aqua_button_mdown_m" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_textinput_normal.png" ), "aqua_textinput_normal" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_textinput_focus.png" ), "aqua_textinput_focus" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_textinput_normal_dl.png" ), "aqua_textinput_normal_dl" ) ) ); @@ -477,29 +517,43 @@ void cEETest::CreateUI() { cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_textinput_normal_ul.png" ), "aqua_textinput_normal_ul" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_textinput_normal_ur.png" ), "aqua_textinput_normal_ur" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_textinput_normal_m.png" ), "aqua_textinput_normal_m" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_checkbox_active_menter.png" ), "aqua_checkbox_active_menter" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_checkbox_active_normal.png" ), "aqua_checkbox_active_normal" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_checkbox_inactive_menter.png" ), "aqua_checkbox_inactive_menter" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_checkbox_inactive_normal.png" ), "aqua_checkbox_inactive_normal" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_radiobutton_active_menter.png" ), "aqua_radiobutton_active_menter" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_radiobutton_active_normal.png" ), "aqua_radiobutton_active_normal" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_radiobutton_inactive_menter.png" ), "aqua_radiobutton_inactive_menter" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_radiobutton_inactive_normal.png" ), "aqua_radiobutton_inactive_normal" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_hslider_button_normal.png" ), "aqua_hslider_button_normal" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_hslider_button_menter.png" ), "aqua_hslider_button_menter" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_hslider_bg_normal_m.png" ), "aqua_hslider_bg_normal_m" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_hslider_bg_normal_ml.png" ), "aqua_hslider_bg_normal_ml" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_hslider_bg_normal_mr.png" ), "aqua_hslider_bg_normal_mr" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_vslider_button_normal.png" ), "aqua_vslider_button_normal" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_vslider_button_menter.png" ), "aqua_vslider_button_menter" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_vslider_bg_normal_m.png" ), "aqua_vslider_bg_normal_m" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_vslider_bg_normal_u.png" ), "aqua_vslider_bg_normal_u" ) ) ); cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_vslider_bg_normal_d.png" ), "aqua_vslider_bg_normal_d" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_spinbox_input_normal_ml.png" ), "aqua_spinbox_input_normal_ml" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_spinbox_input_normal_m.png" ), "aqua_spinbox_input_normal_m" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_spinbox_input_normal_d.png" ), "aqua_spinbox_input_normal_d" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_spinbox_input_normal_dl.png" ), "aqua_spinbox_input_normal_dl" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_spinbox_input_normal_u.png" ), "aqua_spinbox_input_normal_u" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_spinbox_input_normal_ul.png" ), "aqua_spinbox_input_normal_ul" ) ) ); + + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_spinbox_btnup_normal.png" ), "aqua_spinbox_btnup_normal" ) ) ); + cGlobalShapeGroup::instance()->Add( eeNew( cShape, ( TF->Load( MyPath + "data/aqua/aqua_spinbox_btndown_normal.png" ), "aqua_spinbox_btndown_normal" ) ) ); + cUITheme * AquaTheme = eeNew( cUITheme, ( "aqua", "aqua" ) ); cUISkinComplex * AquaTextInput = eeNew( cUISkinComplex, ( "aqua_textinput" ) ); - cUISkinComplex * AquaButton = AquaTextInput->Copy( "aqua_button" ); + cUISkinComplex * AquaButton = eeNew( cUISkinComplex, ( "aqua_button" ) ); cUISkinSimple * AquaCheckboxActive = eeNew( cUISkinSimple, ( "aqua_checkbox_active" ) ); cUISkinSimple * AquaCheckboxInactive = eeNew( cUISkinSimple, ( "aqua_checkbox_inactive" ) ); cUISkinSimple * AquaRadioButtonActive = eeNew( cUISkinSimple, ( "aqua_radiobutton_active" ) ); @@ -508,11 +562,15 @@ void cEETest::CreateUI() { cUISkinSimple * AquaSliderButton = eeNew( cUISkinSimple, ( "aqua_hslider_button" ) ); cUISkinComplex * AquaVSliderBg = eeNew( cUISkinComplex, ( "aqua_vslider_bg" ) ); cUISkinSimple * AquaVSliderButton = eeNew( cUISkinSimple, ( "aqua_vslider_button" ) ); + cUISkinComplex * AquaSpinBox = eeNew( cUISkinComplex, ( "aqua_spinbox_input" ) ); + cUISkinSimple * AquaSpinBoxBtnUp = eeNew( cUISkinSimple, ( "aqua_spinbox_btnup" ) ); + cUISkinSimple * AquaSpinBoxBtnDown = eeNew( cUISkinSimple, ( "aqua_spinbox_btndown" ) ); + AquaTextInput->SetColor ( cUISkin::StateNormal , eeColorA( 240, 240, 255, 255 ) ); AquaTextInput->SetColor ( cUISkin::StateFocus , eeColorA( 250, 250, 255, 255 ) ); - AquaButton->SetColor ( cUISkin::StateMouseEnter , eeColorA( 200, 255, 200, 255 ) ); - AquaButton->SetColor ( cUISkin::StateMouseDown , eeColorA( 150, 255, 150, 255 ) ); + //AquaButton->SetColor ( cUISkin::StateMouseEnter , eeColorA( 200, 255, 200, 255 ) ); + //AquaButton->SetColor ( cUISkin::StateMouseDown , eeColorA( 150, 255, 150, 255 ) ); AquaTheme->Add( AquaTextInput ); AquaTheme->Add( AquaButton ); @@ -524,6 +582,9 @@ void cEETest::CreateUI() { AquaTheme->Add( AquaSliderButton ); AquaTheme->Add( AquaVSliderBg ); AquaTheme->Add( AquaVSliderButton ); + AquaTheme->Add( AquaSpinBox ); + AquaTheme->Add( AquaSpinBoxBtnUp ); + AquaTheme->Add( AquaSpinBoxBtnDown ); /***************/ cUIThemeManager::instance()->Add( AquaTheme ); @@ -1329,25 +1390,6 @@ void cEETest::Particles() { } int main (int argc, char * argv []) { -/* std::string Path( "/home/downloads/files/temp/bnb/allin/" ); -*/ -/* - cTextureGroupLoader * tgl = eeNew( cTextureGroupLoader, () ); - tgl->UpdateTextureAtlas( AppPath() + "data/bnb/bnb.etg", Path ); - eeDelete( tgl ); -*/ -/* - cTexturePacker tp( 512, 512 ); - - if ( argc > 1 ) - Path = std::string( argv[1] ); - - tp.AddTexturesPath( Path ); - - tp.PackTextures(); - - tp.Save( AppPath() + "data/bnb/bnb.png", EE_SAVE_TYPE_PNG ); -*/ cEETest * Test = eeNew( cEETest, () ); Test->Process(); diff --git a/src/ui/cuicheckbox.cpp b/src/ui/cuicheckbox.cpp index 211093398..e02287d86 100644 --- a/src/ui/cuicheckbox.cpp +++ b/src/ui/cuicheckbox.cpp @@ -89,6 +89,8 @@ void cUICheckBox::Active( const bool& active ) { mActive = true; } + + OnValueChange(); } const bool& cUICheckBox::Active() const { diff --git a/src/ui/cuicontrol.cpp b/src/ui/cuicontrol.cpp index 0e400ce15..0e580195b 100644 --- a/src/ui/cuicontrol.cpp +++ b/src/ui/cuicontrol.cpp @@ -310,6 +310,14 @@ Uint32 cUIControl::OnFocusLoss() { return 1; } + +Uint32 cUIControl::OnValueChange() { + SendCommonEvent( cUIEvent::EventOnValueChange ); + + return 1; +} + + Uint32 cUIControl::HAlign() const { return mFlags & UI_HALIGN_MASK; } diff --git a/src/ui/cuicontrol.hpp b/src/ui/cuicontrol.hpp index ffc01d64d..59c7e1627 100644 --- a/src/ui/cuicontrol.hpp +++ b/src/ui/cuicontrol.hpp @@ -146,6 +146,8 @@ class EE_API cUIControl { virtual Uint32 OnFocus(); virtual Uint32 OnFocusLoss(); + + virtual Uint32 OnValueChange(); Uint32 HAlign() const; diff --git a/src/ui/cuievent.hpp b/src/ui/cuievent.hpp index f43b26e89..353223222 100644 --- a/src/ui/cuievent.hpp +++ b/src/ui/cuievent.hpp @@ -31,6 +31,7 @@ class EE_API cUIEvent { EventOnTextChanged, EventOnFontChanged, EventOnPressEnter, + EventOnValueChange, EventUser, EventForceDWord = 0xFFFFFFFF }; diff --git a/src/ui/cuiradiobutton.cpp b/src/ui/cuiradiobutton.cpp index 8028d8a03..ee7bf4419 100644 --- a/src/ui/cuiradiobutton.cpp +++ b/src/ui/cuiradiobutton.cpp @@ -88,19 +88,23 @@ void cUIRadioButton::Active( const bool& active ) { mInactiveButton->Visible( true ); mActive = false; + + OnValueChange(); } } else { mActiveButton->Visible( true ); mInactiveButton->Visible( false ); mActive = true; + + OnValueChange(); } if ( active && NULL != mParentCtrl ) { cUIControl * tChild = mParentCtrl->ChildGetFirst(); while ( NULL != tChild ) { - if ( tChild->Type() & UI_TYPE_GET( UI_TYPE_RADIOBUTTON ) ) { + if ( tChild->IsType( UI_TYPE_RADIOBUTTON ) ) { if ( tChild != this ) { cUIRadioButton * tRB = reinterpret_cast ( tChild ); @@ -119,7 +123,7 @@ bool cUIRadioButton::CheckActives() { cUIControl * tChild = mParentCtrl->ChildGetFirst(); while ( NULL != tChild ) { - if ( tChild->Type() & UI_TYPE_GET( UI_TYPE_RADIOBUTTON ) ) { + if ( tChild->IsType( UI_TYPE_RADIOBUTTON ) ) { if ( tChild != this ) { cUIRadioButton * tRB = reinterpret_cast ( tChild ); @@ -142,7 +146,7 @@ void cUIRadioButton::AutoActivate() { cUIControl * tChild = mParentCtrl->ChildGetFirst(); while ( NULL != tChild ) { - if ( tChild->Type() & UI_TYPE_GET( UI_TYPE_RADIOBUTTON ) ) { + if ( tChild->IsType( UI_TYPE_RADIOBUTTON ) ) { if ( tChild != this ) { cUIRadioButton * tRB = reinterpret_cast ( tChild ); diff --git a/src/ui/cuislider.cpp b/src/ui/cuislider.cpp index 6eb3183a3..68787a053 100644 --- a/src/ui/cuislider.cpp +++ b/src/ui/cuislider.cpp @@ -141,6 +141,8 @@ void cUISlider::Value( const eeFloat& Val ) { else mSlider->Pos( mSlider->Pos().x, mBackSlider->Size().Height() * ( Val - mMinValue ) ); } + + OnValueChange(); } } diff --git a/src/ui/cuispinbox.cpp b/src/ui/cuispinbox.cpp new file mode 100644 index 000000000..20cdd7213 --- /dev/null +++ b/src/ui/cuispinbox.cpp @@ -0,0 +1,204 @@ +#include "cuispinbox.hpp" + +namespace EE { namespace UI { + +cUISpinBox::cUISpinBox( const cUISpinBox::CreateParams& Params ) : + cUIControlAnim( Params ), + mMinValue( 0.f ), + mMaxValue( 1024.f ), + mValue( Params.DefaultValue ), + mClickStep( 1.f ) +{ + mType |= UI_TYPE_GET(UI_TYPE_SPINBOX); + + cUITextInput::CreateParams InputParams( Params ); + InputParams.PosSet( 0, 0 ); + InputParams.Parent( this ); + + mInput = eeNew( cUITextInput, ( InputParams ) ); + + cUIPushButton::CreateParams BtnParams( Params ); + BtnParams.Parent( this ); + BtnParams.Size = eeSize( 16, 16 ); + + mPushUp = eeNew( cUIPushButton, ( BtnParams ) ); + mPushDown = eeNew( cUIPushButton, ( BtnParams ) ); + + mInput->Visible ( true ); + mInput->Enabled ( true ); + mPushUp->Visible ( true ); + mPushUp->Enabled ( true ); + mPushDown->Visible ( true ); + mPushDown->Enabled ( true ); + + mInput->GetInputTextBuffer()->AllowOnlyNumbers( true, Params.AllowDotsInNumbers ); + + InternalValue( mValue, true ); + + AdjustChilds(); +} + +cUISpinBox::~cUISpinBox() { + +} + +void cUISpinBox::SetTheme( cUITheme * Theme ) { + cUIControl::SetTheme ( Theme, "spinbox" ); + + mInput->ForceThemeSkin ( Theme, "spinbox_input" ); + mPushUp->ForceThemeSkin ( Theme, "spinbox_btnup" ); + mPushDown->ForceThemeSkin ( Theme, "spinbox_btndown" ); + + cShape * tShape = NULL; + cUISkin * tSkin = NULL; + + tSkin = mPushUp->GetSkin(); + + if ( NULL != tSkin ) { + tShape = tSkin->GetShape( cUISkin::StateNormal ); + + if ( NULL != tShape ) { + mPushUp->Size( tShape->RealSize() ); + } + } + + tSkin = mPushDown->GetSkin(); + + if ( NULL != tSkin ) { + tShape = tSkin->GetShape( cUISkin::StateNormal ); + + if ( NULL != tShape ) { + mPushDown->Size( tShape->RealSize() ); + } + } + + AdjustChilds(); +} + +void cUISpinBox::AdjustChilds() { + mPushUp->Pos( mSize.Width() - mPushUp->Size().Width(), 0 ); + mPushDown->Pos( mSize.Width() - mPushDown->Size().Width(), mPushUp->Size().Height() ); + mInput->Size( mSize.Width() - mPushUp->Size().Width(), mSize.Height() ); +} + +void cUISpinBox::Padding( const eeRectf& padding ) { + mInput->Padding( padding ); +} + +const eeRectf& cUISpinBox::Padding() const { + return mInput->Padding(); +} + +void cUISpinBox::ClickStep( const eeFloat& step ) { + mClickStep = step; +} + +const eeFloat& cUISpinBox::ClickStep() const { + return mClickStep; +} + +Uint32 cUISpinBox::OnMessage( const cUIMessage * Msg ) { + switch ( Msg->Msg() ) { + case cUIMessage::MsgClick: + { + if ( Msg->Flags() & EE_BUTTON_LMASK ) { + if ( Msg->Sender() == mPushUp ) { + AddValue( mClickStep ); + } else if ( Msg->Sender() == mPushDown ) { + AddValue( -mClickStep ); + } + } else if ( Msg->Flags() & EE_BUTTONS_WUWD ) { + if ( Msg->Flags() & EE_BUTTON( EE_BUTTON_WHEELUP ) ) + AddValue( mClickStep ); + else + AddValue( -mClickStep ); + } + + return 1; + } + } + + return 0; +} + +void cUISpinBox::AddValue( const eeFloat& value ) { + if ( !mInput->Text().size() ) + mInput->Text( L"0" ); + + Value( mValue + value ); +} + +void cUISpinBox::InternalValue( const eeFloat& Val, const bool& Force ) { + if ( Force || Val != mValue ) { + if ( Val >= mMinValue && Val <= mMaxValue ) { + eeFloat iValN = (Int32) Val; + eeFloat fValN = (eeFloat)iValN; + + if ( fValN == Val ) { + mInput->Text( toWStr( iValN ) ); + } else { + mInput->Text( toWStr( Val ) ); + } + + mValue = Val; + + OnValueChange(); + } + } +} + +void cUISpinBox::Value( const eeFloat& Val ) { + InternalValue( Val, false ); +} + +const eeFloat& cUISpinBox::Value() const { + return mValue; +} + +void cUISpinBox::MinValue( const eeFloat& MinVal ) { + mMinValue = MinVal; + + if ( mValue < mMinValue ) + mValue = mMinValue; +} + +const eeFloat& cUISpinBox::MinValue() const { + return mMinValue; +} + +void cUISpinBox::MaxValue( const eeFloat& MaxVal ) { + mMaxValue = MaxVal; + + if ( mValue > mMaxValue ) + mValue = mMaxValue; +} + +const eeFloat& cUISpinBox::MaxValue() const { + return mMaxValue; +} + +void cUISpinBox::Update() { + cUIControlAnim::Update(); + + if ( mInput->GetInputTextBuffer()->ChangedSinceLastUpdate() ) { + if ( !mInput->Text().size() ) { + Value( 0 ); + } else { + eeFloat Val = mValue; + + if ( L'.' == mInput->Text()[ mInput->Text().size() - 1 ] ) { + Uint32 pos = mInput->Text().find_first_of( L"." ); + + if ( pos != mInput->Text().size() - 1 ) + mInput->Text( mInput->Text().substr( 0, mInput->Text().size() - 1 ) ); + } else { + bool Res = fromWString( Val, mInput->Text() ); + + if ( Res ) + Value( Val ); + } + } + } +} + +}} diff --git a/src/ui/cuispinbox.hpp b/src/ui/cuispinbox.hpp new file mode 100644 index 000000000..01f638167 --- /dev/null +++ b/src/ui/cuispinbox.hpp @@ -0,0 +1,74 @@ +#ifndef EE_UICUISPINBOX_HPP +#define EE_UICUISPINBOX_HPP + +#include "cuitextinput.hpp" +#include "cuipushbutton.hpp" + +namespace EE { namespace UI { + +class EE_API cUISpinBox : public cUIControlAnim { + public: + class CreateParams : public cUITextInput::CreateParams { + public: + inline CreateParams() : + cUITextInput::CreateParams() + { + MaxLenght = 24; + DefaultValue = 0.f; + } + + inline ~CreateParams() {} + + eeFloat DefaultValue; + bool AllowDotsInNumbers; + }; + + cUISpinBox( const cUISpinBox::CreateParams& Params ); + + ~cUISpinBox(); + + virtual void SetTheme( cUITheme * Theme ); + + virtual void Padding( const eeRectf& padding ); + + const eeRectf& Padding() const; + + virtual void ClickStep( const eeFloat& step ); + + const eeFloat& ClickStep() const; + + virtual Uint32 OnMessage( const cUIMessage * Msg ); + + void AddValue( const eeFloat& value ); + + virtual void MinValue( const eeFloat& MinVal ); + + const eeFloat& MinValue() const; + + virtual void MaxValue( const eeFloat& MaxVal ); + + const eeFloat& MaxValue() const; + + virtual void Value( const eeFloat& Val ); + + const eeFloat& Value() const; + + virtual void Update(); + protected: + cUITextInput * mInput; + cUIPushButton * mPushUp; + cUIPushButton * mPushDown; + eeFloat mMinValue; + eeFloat mMaxValue; + eeFloat mValue; + eeFloat mClickStep; + + void AdjustChilds(); + + void InternalValue( const eeFloat& Val, const bool& Force = false ); + +}; + +}} + +#endif diff --git a/src/ui/cuitextbox.cpp b/src/ui/cuitextbox.cpp index 961bb81f3..b77ae2f6e 100644 --- a/src/ui/cuitextbox.cpp +++ b/src/ui/cuitextbox.cpp @@ -29,7 +29,7 @@ void cUITextBox::Draw() { if ( IsClipped() ) cUIManager::instance()->ClipEnable( mScreenPos.x + (Int32)mPadding.Left, mScreenPos.y + (Int32)mPadding.Top, mSize.Width() + (Int32)mPadding.Right, mSize.Height() + (Int32)mPadding.Bottom ); - mTextCache.Draw( (eeFloat)mScreenPos.x + mAlignOffset.x + mPadding.Left + 1, (eeFloat)mScreenPos.y + mAlignOffset.y + mPadding.Top, Flags(), 1.f, 0.f, mBlend ); + mTextCache.Draw( (eeFloat)mScreenPos.x + mAlignOffset.x + mPadding.Left + 1.f, (eeFloat)mScreenPos.y + mAlignOffset.y + mPadding.Top, Flags(), 1.f, 0.f, mBlend ); if ( IsClipped() ) cUIManager::instance()->ClipDisable(); @@ -105,7 +105,7 @@ void cUITextBox::AutoSize() { void cUITextBox::AutoAlign() { switch ( FontHAlignGet( Flags() ) ) { case UI_HALIGN_CENTER: - mAlignOffset.x = ( (eeFloat)mSize.x - (eeFloat)mTextCache.GetTextWidth() ) * 0.5f; + mAlignOffset.x = (eeFloat)( (Int32)( mSize.x - mTextCache.GetTextWidth() ) / 2 ); break; case UI_HALIGN_RIGHT: mAlignOffset.x = ( (eeFloat)mSize.x - (eeFloat)mTextCache.GetTextWidth() ); @@ -117,7 +117,7 @@ void cUITextBox::AutoAlign() { switch ( FontVAlignGet( Flags() ) ) { case UI_VALIGN_CENTER: - mAlignOffset.y = ( (eeFloat)mSize.y - (eeFloat)mTextCache.GetTextHeight() ) * 0.5f; + mAlignOffset.y = (eeFloat)( ( (Int32)( mSize.y - mTextCache.GetTextHeight() ) ) / 2 ); break; case UI_VALIGN_BOTTOM: mAlignOffset.y = ( (eeFloat)mSize.y - (eeFloat)mTextCache.GetTextHeight() ); diff --git a/src/ui/cuitextbox.hpp b/src/ui/cuitextbox.hpp index c18482d33..9ff62c887 100644 --- a/src/ui/cuitextbox.hpp +++ b/src/ui/cuitextbox.hpp @@ -32,11 +32,11 @@ class EE_API cUITextBox : public cUIControlAnim { void Font( cFont * font ); - const std::wstring& Text(); + virtual const std::wstring& Text(); - void Text( const std::wstring& text ); + virtual void Text( const std::wstring& text ); - void Text( const std::string& text ); + virtual void Text( const std::string& text ); const eeColorA& Color() const; diff --git a/src/ui/cuitextinput.cpp b/src/ui/cuitextinput.cpp index 4333aacc2..9825b5f61 100644 --- a/src/ui/cuitextinput.cpp +++ b/src/ui/cuitextinput.cpp @@ -8,10 +8,9 @@ cUITextInput::cUITextInput( const cUITextInput::CreateParams& Params ) : mCursorPos(0) { mType |= UI_TYPE_GET(UI_TYPE_TEXTINPUT); - + mTextBuffer.Start(); mTextBuffer.Active( false ); - mTextBuffer.SupportNewLine( Params.SupportNewLine ); mTextBuffer.SupportFreeEditing( Params.SupportFreeEditing ); mTextBuffer.MaxLenght( Params.MaxLenght ); mTextBuffer.SetReturnCallback( cb::Make0( this, &cUITextInput::PrivOnPressEnter ) ); @@ -138,4 +137,22 @@ void cUITextInput::SetTheme( cUITheme * Theme ) { cUIControl::SetTheme( Theme, "textinput" ); } +cInputTextBuffer * cUITextInput::GetInputTextBuffer() { + return &mTextBuffer; +} + +void cUITextInput::Text( const std::wstring& text ) { + cUITextBox::Text( text ); + + mTextBuffer.Buffer( text ); +} + +void cUITextInput::Text( const std::string& text ) { + cUITextBox::Text( text ); +} + +const std::wstring& cUITextInput::Text() { + return cUITextBox::Text(); +} + }} diff --git a/src/ui/cuitextinput.hpp b/src/ui/cuitextinput.hpp index 98f93cddf..059d5cfce 100644 --- a/src/ui/cuitextinput.hpp +++ b/src/ui/cuitextinput.hpp @@ -10,15 +10,15 @@ class EE_API cUITextInput : public cUITextBox { public: class CreateParams : public cUITextBox::CreateParams { public: - inline CreateParams() : cUITextBox::CreateParams() { - SupportNewLine = true; - SupportFreeEditing = true; - MaxLenght = 256; + inline CreateParams() : + cUITextBox::CreateParams(), + SupportFreeEditing( true ), + MaxLenght( 256 ) + { } inline ~CreateParams() {} - bool SupportNewLine; bool SupportFreeEditing; Uint32 MaxLenght; }; @@ -37,9 +37,17 @@ class EE_API cUITextInput : public cUITextBox { virtual Uint32 OnPressEnter(); + virtual void Text( const std::wstring& text ); + + virtual void Text( const std::string& text ); + + virtual const std::wstring& Text(); + void PushIgnoredChar( const Uint32& ch ); virtual void SetTheme( cUITheme * Theme ); + + cInputTextBuffer * GetInputTextBuffer(); protected: cInputTextBuffer mTextBuffer; bool mShowingWait; diff --git a/src/ui/uihelper.hpp b/src/ui/uihelper.hpp index 131140ade..031acd518 100644 --- a/src/ui/uihelper.hpp +++ b/src/ui/uihelper.hpp @@ -44,12 +44,13 @@ Uint32 EE_API VAlignGet( Uint32 Flags ); #define UI_TYPE_CONTROL (0) #define UI_TYPE_CONTROL_ANIM (1) #define UI_TYPE_GFX (2) -#define UI_TYPE_TEXTBOX (3) +#define UI_TYPE_TEXTBOX (3) #define UI_TYPE_TEXTINPUT (4) #define UI_TYPE_PUSHBUTTON (5) #define UI_TYPE_CHECKBOX (6) #define UI_TYPE_RADIOBUTTON (7) #define UI_TYPE_SLIDER (8) +#define UI_TYPE_SPINBOX (9) #define UI_TYPE_GET(X) ( 1 << (X) ) diff --git a/src/utils/string.cpp b/src/utils/string.cpp index 2d32281d0..ca038954a 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -6,7 +6,10 @@ bool isCharacter( const eeInt& mValue ) { return (mValue >= 32 && mValue <= 126) || (mValue >= 161 && mValue <= 255) || (mValue == 9); } -bool isNumber( const eeInt& mValue ) { +bool isNumber( const eeInt& mValue, bool AllowDot ) { + if ( AllowDot ) + return ( mValue >= 48 && mValue <= 57 ) || mValue == 46; + return mValue >= 48 && mValue <= 57; } diff --git a/src/utils/string.hpp b/src/utils/string.hpp index c7d5700c8..e34059edf 100755 --- a/src/utils/string.hpp +++ b/src/utils/string.hpp @@ -9,7 +9,7 @@ namespace EE { namespace Utils { bool EE_API isCharacter( const eeInt& mValue ); /** @return If the value passed is a number */ -bool EE_API isNumber( const eeInt& mValue ); +bool EE_API isNumber( const eeInt& mValue, bool AllowDot = false ); /** @return If the value passed is a letter */ bool EE_API isLetter( const eeInt& mValue ); diff --git a/src/window/cinputtextbuffer.cpp b/src/window/cinputtextbuffer.cpp index e3ef27f2b..3712e24b3 100755 --- a/src/window/cinputtextbuffer.cpp +++ b/src/window/cinputtextbuffer.cpp @@ -3,13 +3,15 @@ namespace EE { namespace Window { cInputTextBuffer::cInputTextBuffer( const bool& Active, const bool& SupportNewLine, const bool& SupportFreeEditing, const Uint32& MaxLenght ) : + mActive( Active ), + mFlags(0), mChangeSinceLastUpdate(false), mCallback(0), mPromptPos(0), mPromptAutoPos(true) { - mActive = Active; - mSupportNewLine = SupportNewLine; + this->SupportNewLine( SupportNewLine ); + mPromtPosSupport = SupportFreeEditing; mMaxLenght = MaxLenght; SetAutoPromp(); @@ -17,12 +19,13 @@ cInputTextBuffer::cInputTextBuffer( const bool& Active, const bool& SupportNewLi cInputTextBuffer::cInputTextBuffer() : mActive(true), - mSupportNewLine(true), + mFlags(0), mChangeSinceLastUpdate(false), mCallback(0), mPromtPosSupport(true), mMaxLenght(0xFFFFFFFF) { + SupportNewLine( false ); SetAutoPromp(); } @@ -63,7 +66,7 @@ void cInputTextBuffer::Update( EE_Event* Event ) { } } } else if ( ( c == KEY_RETURN || c == KEY_KP_ENTER ) && !cInput::instance()->MetaPressed() && !cInput::instance()->AltPressed() && !cInput::instance()->ControlPressed() ) { - if ( mSupportNewLine && CanAdd() ) { + if ( SupportNewLine() && CanAdd() ) { InsertChar( mText, mPromptPos, L'\n' ); mPromptPos++; } @@ -86,6 +89,10 @@ void cInputTextBuffer::Update( EE_Event* Event ) { } else if ( CanAdd() && isCharacter(c) && !cInput::instance()->MetaPressed() && !cInput::instance()->AltPressed() && !cInput::instance()->ControlPressed() ) { bool Ignored = false; + if ( AllowOnlyNumbers() && !isNumber( c, AllowDotsInNumbers() ) ) { + Ignored = true; + } + if ( mIgnoredChars.size() ) { for ( eeUint i = 0; i < mIgnoredChars.size(); i++ ) { if ( mIgnoredChars[i] == (Uint32)c ) @@ -125,13 +132,15 @@ void cInputTextBuffer::Update( EE_Event* Event ) { if ( c == KEY_BACKSPACE && mText.size() > 0 ) { mText.resize( mText.size() - 1 ); } else if ( (c == KEY_RETURN || c == KEY_KP_ENTER) && !cInput::instance()->MetaPressed() && !cInput::instance()->AltPressed() && !cInput::instance()->ControlPressed() ) { - if ( mSupportNewLine && CanAdd() ) + if ( SupportNewLine() && CanAdd() ) mText += L'\n'; if ( mEnterCall.IsSet() ) mEnterCall(); } else if ( CanAdd() && isCharacter(c) && !cInput::instance()->MetaPressed() && !cInput::instance()->AltPressed() && !cInput::instance()->ControlPressed() ) { - mText += c; + if ( !( AllowOnlyNumbers() && !isNumber( c, AllowDotsInNumbers() ) ) ) { + mText += c; + } } } } @@ -161,9 +170,11 @@ void cInputTextBuffer::SetAutoPromp( const bool& set ) { } void cInputTextBuffer::Buffer( const std::wstring& str ) { - mText = str; - mChangeSinceLastUpdate = true; - + if ( mText != str ) { + mText = str; + mChangeSinceLastUpdate = true; + } + if ( mPromtPosSupport ) SetAutoPromp(); } @@ -213,4 +224,45 @@ const Uint32& cInputTextBuffer::MaxLenght() const { return mMaxLenght; } +std::wstring cInputTextBuffer::Buffer() const { + return mText; +} + +bool cInputTextBuffer::Active() const { + return mActive; +} + +void cInputTextBuffer::Active( const bool& Active ) { + mActive = Active; +} + +bool cInputTextBuffer::SupportNewLine() { + return 0 != ( mFlags & ( 1 << INPUT_TB_SUPPORT_NEW_LINE ) ); +} + +void cInputTextBuffer::SupportNewLine( const bool& SupportNewLine ) { + Write32BitKey( &mFlags, INPUT_TB_SUPPORT_NEW_LINE, SupportNewLine == true ); +} + +void cInputTextBuffer::AllowOnlyNumbers( const bool& onlynums, const bool& allowdots ) { + Write32BitKey( &mFlags, INPUT_TB_ALLOW_ONLY_NUMBERS, onlynums == true ); + Write32BitKey( &mFlags, INPUT_TB_ALLOW_DOT_IN_NUMBERS, allowdots == true ); +} + +bool cInputTextBuffer::AllowOnlyNumbers() { + return 0 != ( mFlags & ( 1 << INPUT_TB_ALLOW_ONLY_NUMBERS ) ); +} + +bool cInputTextBuffer::AllowDotsInNumbers() { + return 0 != ( mFlags & ( 1 << INPUT_TB_ALLOW_DOT_IN_NUMBERS ) ); +} + +bool cInputTextBuffer::SupportFreeEditing() const { + return mPromtPosSupport; +} + +void cInputTextBuffer::SupportFreeEditing( const bool& SupportNewLine ) { + mPromtPosSupport = SupportNewLine; +} + }} diff --git a/src/window/cinputtextbuffer.hpp b/src/window/cinputtextbuffer.hpp index 1fc82f708..de6880bdb 100755 --- a/src/window/cinputtextbuffer.hpp +++ b/src/window/cinputtextbuffer.hpp @@ -6,6 +6,10 @@ namespace EE { namespace Window { +#define INPUT_TB_SUPPORT_NEW_LINE (0) +#define INPUT_TB_ALLOW_ONLY_NUMBERS (1) +#define INPUT_TB_ALLOW_DOT_IN_NUMBERS (2) + class EE_API cInputTextBuffer { public: typedef cb::Callback0 EnterCallback; @@ -15,28 +19,37 @@ class EE_API cInputTextBuffer { ~cInputTextBuffer(); /** @return The current buffer */ - std::wstring Buffer() const { return mText; }; + std::wstring Buffer() const; /** Set a new current buffer */ void Buffer( const std::wstring& str ); /** @return If input buffer is active */ - bool Active() const { return mActive; } + bool Active() const; /** Set the state of the input buffer */ - void Active( const bool& Active ) { mActive = Active; } + void Active( const bool& Active ); /** @return If new line is supported */ - bool SupportNewLine() const { return mSupportNewLine; } + bool SupportNewLine(); /** Support new line consist of allowing to add a new line when key return is pressed. */ - void SupportNewLine( const bool& SupportNewLine ) { mSupportNewLine = SupportNewLine; } + void SupportNewLine( const bool& SupportNewLine ); /** @return If Free Editing is enabled */ - bool SupportFreeEditing() const { return mPromtPosSupport; } + bool SupportFreeEditing() const; /** Free editing consist on the capability of moving the cursor position over the buffer, to write over the buffer, and not only after the last character. */ - void SupportFreeEditing( const bool& SupportNewLine ) { mPromtPosSupport = SupportNewLine; } + void SupportFreeEditing( const bool& SupportNewLine ); + + /** Block all the inserts, allow only numeric characters. */ + void AllowOnlyNumbers( const bool& onlynums, const bool& allowdots = false ); + + /** @return If is only allowing numbers */ + bool AllowOnlyNumbers(); + + /** @return If is only allowing numbers, it allow floating point numbers? */ + bool AllowDotsInNumbers(); /** Start the input buffer */ void Start(); @@ -78,7 +91,7 @@ class EE_API cInputTextBuffer { std::wstring mText; bool mActive; - bool mSupportNewLine; + Uint32 mFlags; bool mChangeSinceLastUpdate; Uint32 mCallback;