| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923 |
- #include "Base.h"
- #include "Container.h"
- #include "Layout.h"
- #include "AbsoluteLayout.h"
- #include "FlowLayout.h"
- #include "VerticalLayout.h"
- #include "Label.h"
- #include "Button.h"
- #include "CheckBox.h"
- #include "RadioButton.h"
- #include "Slider.h"
- #include "TextBox.h"
- #include "Joystick.h"
- #include "ImageControl.h"
- #include "Game.h"
- namespace gameplay
- {
- // If the user stops scrolling for this amount of time (in millis) before touch/click release, don't apply inertia.
- static const long SCROLL_INERTIA_DELAY = 100L;
- // Factor to multiply friction by before applying to velocity.
- static const float SCROLL_FRICTION_FACTOR = 5.0f;
- // Distance that must be scrolled before isScrolling() will return true, used e.g. to cancel button-click events.
- static const float SCROLL_THRESHOLD = 10.0f;
- // Distance a joystick must be pushed in order to trigger focus-change and/or scrolling.
- static const float JOYSTICK_THRESHOLD = 0.75f;
- // Scroll speed when using a DPad -- max scroll speed when using a joystick.
- static const float GAMEPAD_SCROLL_SPEED = 500.0f;
- // If the DPad or joystick is held down, this is the initial delay in milliseconds between focus change events.
- static const float FOCUS_CHANGE_REPEAT_DELAY = 300.0f;
- /**
- * Sort function for use with _controls.sort(), based on Z-Order.
- *
- * @param c1 The first control
- * @param c2 The second control
- * return true if the first controls z index is less than the second.
- */
- static bool sortControlsByZOrder(Control* c1, Control* c2);
- void Container::clearContacts()
- {
- for (int i = 0; i < MAX_CONTACT_INDICES; ++i)
- _contactIndices[i] = false;
- }
- Container::Container()
- : _layout(NULL), _scrollBarTopCap(NULL), _scrollBarVertical(NULL), _scrollBarBottomCap(NULL),
- _scrollBarLeftCap(NULL), _scrollBarHorizontal(NULL), _scrollBarRightCap(NULL),
- _scroll(SCROLL_NONE), _scrollBarBounds(Rectangle::empty()), _scrollPosition(Vector2::zero()),
- _scrollBarsAutoHide(false), _scrollBarOpacity(1.0f), _scrolling(false),
- _scrollingVeryFirstX(0), _scrollingVeryFirstY(0), _scrollingFirstX(0), _scrollingFirstY(0), _scrollingLastX(0), _scrollingLastY(0),
- _scrollingStartTimeX(0), _scrollingStartTimeY(0), _scrollingLastTime(0),
- _scrollingVelocity(Vector2::zero()), _scrollingFriction(1.0f), _scrollWheelSpeed(400.0f),
- _scrollingRight(false), _scrollingDown(false),
- _scrollingMouseVertically(false), _scrollingMouseHorizontally(false),
- _scrollBarOpacityClip(NULL), _zIndexDefault(0), _focusIndexDefault(0), _focusIndexMax(0),
- _focusPressed(0), _selectButtonDown(false),
- _lastFrameTime(0), _focusChangeRepeat(false),
- _focusChangeStartTime(0), _focusChangeRepeatDelay(FOCUS_CHANGE_REPEAT_DELAY), _focusChangeCount(0),
- _totalWidth(0), _totalHeight(0),
- _initializedWithScroll(false), _scrollWheelRequiresFocus(false)
- {
- clearContacts();
- }
- Container::~Container()
- {
- std::vector<Control*>::iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- SAFE_RELEASE((*it));
- }
- SAFE_RELEASE(_layout);
- }
- Container* Container::create(const char* id, Theme::Style* style, Layout::Type layoutType)
- {
- GP_ASSERT(style);
- Container* container = Container::create(layoutType);
- if (id)
- container->_id = id;
- container->_style = style;
- return container;
- }
- Container* Container::create(Layout::Type type)
- {
- Layout* layout = NULL;
- switch (type)
- {
- case Layout::LAYOUT_ABSOLUTE:
- layout = AbsoluteLayout::create();
- break;
- case Layout::LAYOUT_FLOW:
- layout = FlowLayout::create();
- break;
- case Layout::LAYOUT_VERTICAL:
- layout = VerticalLayout::create();
- break;
- }
- Container* container = new Container();
- container->_layout = layout;
- return container;
- }
- Container* Container::create(Theme::Style* style, Properties* properties, Theme* theme)
- {
- GP_ASSERT(properties);
- const char* layoutString = properties->getString("layout");
- Container* container = Container::create(getLayoutType(layoutString));
- container->initialize(style, properties);
- container->_scroll = getScroll(properties->getString("scroll"));
- container->_scrollBarsAutoHide = properties->getBool("scrollBarsAutoHide");
- if (container->_scrollBarsAutoHide)
- {
- container->_scrollBarOpacity = 0.0f;
- }
-
- container->_scrollWheelRequiresFocus = properties->getBool("scrollWheelRequiresFocus");
- if (properties->exists("scrollingFriction"))
- container->_scrollingFriction = properties->getFloat("scrollingFriction");
- if (properties->exists("scrollWheelSpeed"))
- container->_scrollWheelSpeed = properties->getFloat("scrollWheelSpeed");
- container->addControls(theme, properties);
- container->_layout->update(container, container->_scrollPosition);
- return container;
- }
- void Container::addControls(Theme* theme, Properties* properties)
- {
- GP_ASSERT(theme);
- GP_ASSERT(properties);
- // Add all the controls to this container.
- Properties* controlSpace = properties->getNextNamespace();
- while (controlSpace != NULL)
- {
- Control* control = NULL;
- const char* controlStyleName = controlSpace->getString("style");
- Theme::Style* controlStyle = NULL;
- if (controlStyleName)
- {
- controlStyle = theme->getStyle(controlStyleName);
- }
- else
- {
- controlStyle = theme->getEmptyStyle();
- }
- std::string controlName(controlSpace->getNamespace());
- std::transform(controlName.begin(), controlName.end(), controlName.begin(), (int(*)(int))toupper);
- if (controlName == "LABEL")
- {
- control = Label::create(controlStyle, controlSpace);
- }
- else if (controlName == "BUTTON")
- {
- control = Button::create(controlStyle, controlSpace);
- }
- else if (controlName == "CHECKBOX")
- {
- control = CheckBox::create(controlStyle, controlSpace);
- }
- else if (controlName == "RADIOBUTTON")
- {
- control = RadioButton::create(controlStyle, controlSpace);
- }
- else if (controlName == "CONTAINER")
- {
- control = Container::create(controlStyle, controlSpace, theme);
- }
- else if (controlName == "SLIDER")
- {
- control = Slider::create(controlStyle, controlSpace);
- }
- else if (controlName == "TEXTBOX")
- {
- control = TextBox::create(controlStyle, controlSpace);
- }
- else if (controlName == "JOYSTICK")
- {
- control = Joystick::create(controlStyle, controlSpace);
- }
- else if (controlName == "IMAGE")
- {
- control = ImageControl::create(controlStyle, controlSpace);
- }
- else
- {
- // Ignore - not a valid control name.
- // This used to fail, but I see no reason to hard fail here (this also fixes not being able
- // to set padding on containers).
- }
- // Add the new control to the form.
- if (control)
- {
- addControl(control);
- control->release();
- }
- // Get the next control.
- controlSpace = properties->getNextNamespace();
- }
- // Sort controls by Z-Order.
- sortControls();
- }
- Layout* Container::getLayout()
- {
- return _layout;
- }
- unsigned int Container::addControl(Control* control)
- {
- GP_ASSERT(control);
- if (control->_parent && control->_parent != this)
- {
- control->_parent->removeControl(control);
- }
- if (control->getZIndex() == -1)
- {
- control->setZIndex(_zIndexDefault++);
- }
- if (control->getFocusIndex() == -1)
- {
- control->setFocusIndex(_focusIndexDefault++);
- }
- int focusIndex = control->getFocusIndex();
- if (focusIndex > _focusIndexMax)
- _focusIndexMax = focusIndex;
- if (control->_parent != this)
- {
- _controls.push_back(control);
- control->addRef();
- control->_parent = this;
- sortControls();
- return (unsigned int)(_controls.size() - 1);
- }
- else
- {
- // Control is already in this container.
- // Do nothing but determine and return control's index.
- const size_t size = _controls.size();
- for (size_t i = 0; i < size; ++i)
- {
- Control* c = _controls[i];
- if (c == control)
- {
- return (unsigned int)i;
- }
- }
- // Should never reach this.
- GP_ASSERT(false);
- return 0;
- }
- }
- void Container::insertControl(Control* control, unsigned int index)
- {
- GP_ASSERT(control);
- if (control->_parent && control->_parent != this)
- {
- control->_parent->removeControl(control);
- }
- if (control->_parent != this)
- {
- std::vector<Control*>::iterator it = _controls.begin() + index;
- _controls.insert(it, control);
- control->addRef();
- control->_parent = this;
- }
- }
- void Container::removeControl(unsigned int index)
- {
- GP_ASSERT(index < _controls.size());
- std::vector<Control*>::iterator it = _controls.begin() + index;
- Control* control = *it;
- _controls.erase(it);
- control->_parent = NULL;
- SAFE_RELEASE(control);
- }
- void Container::removeControl(const char* id)
- {
- GP_ASSERT(id);
- std::vector<Control*>::iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- Control* c = *it;
- if (strcmp(id, c->getId()) == 0)
- {
- c->_parent = NULL;
- SAFE_RELEASE(c);
- _controls.erase(it);
- return;
- }
- }
- }
- void Container::removeControl(Control* control)
- {
- GP_ASSERT(control);
- std::vector<Control*>::iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- if (*it == control)
- {
- control->_parent = NULL;
- SAFE_RELEASE(control);
- _controls.erase(it);
- return;
- }
- }
- }
- Control* Container::getControl(unsigned int index) const
- {
- std::vector<Control*>::const_iterator it = _controls.begin() + index;
- return *it;
- }
- Control* Container::getControl(const char* id) const
- {
- GP_ASSERT(id);
- std::vector<Control*>::const_iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- Control* c = *it;
- GP_ASSERT(c);
- if (strcmp(id, c->getId()) == 0)
- {
- return c;
- }
- else if (c->isContainer())
- {
- Control* cc = ((Container*)c)->getControl(id);
- if (cc)
- {
- return cc;
- }
- }
- }
- return NULL;
- }
- const std::vector<Control*>& Container::getControls() const
- {
- return _controls;
- }
- void Container::setScroll(Scroll scroll)
- {
- if (scroll != _scroll)
- {
- _scroll = scroll;
- _dirty = true;
- }
- }
- Container::Scroll Container::getScroll() const
- {
- return _scroll;
- }
- void Container::setScrollBarsAutoHide(bool autoHide)
- {
- if (autoHide != _scrollBarsAutoHide)
- {
- _scrollBarsAutoHide = autoHide;
- _dirty = true;
- }
- }
- bool Container::isScrollBarsAutoHide() const
- {
- return _scrollBarsAutoHide;
- }
- bool Container::isScrolling() const
- {
- if (_parent && _parent->isScrolling())
- return true;
- return (_scrolling &&
- (abs(_scrollingLastX - _scrollingVeryFirstX) > SCROLL_THRESHOLD ||
- abs(_scrollingLastY - _scrollingVeryFirstY) > SCROLL_THRESHOLD));
- }
- const Vector2& Container::getScrollPosition() const
- {
- return _scrollPosition;
- }
- void Container::setScrollPosition(const Vector2& scrollPosition)
- {
- _scrollPosition = scrollPosition;
- }
- Animation* Container::getAnimation(const char* id) const
- {
- std::vector<Control*>::const_iterator itr = _controls.begin();
- std::vector<Control*>::const_iterator end = _controls.end();
- Control* control = NULL;
- for (; itr != end; itr++)
- {
- control = *itr;
- GP_ASSERT(control);
- Animation* animation = control->getAnimation(id);
- if (animation)
- return animation;
- if (control->isContainer())
- {
- animation = ((Container*)control)->getAnimation(id);
- if (animation)
- return animation;
- }
- }
- return NULL;
- }
- const char* Container::getType() const
- {
- return "container";
- }
- bool Container::getScrollWheelRequiresFocus() const
- {
- return _scrollWheelRequiresFocus;
- }
- void Container::setScrollWheelRequiresFocus(bool required)
- {
- _scrollWheelRequiresFocus = required;
- }
- void Container::update(const Control* container, const Vector2& offset)
- {
- // Update this container's viewport.
- Control::update(container, offset);
- // Get scrollbar images and diminish clipping bounds to make room for scrollbars.
- if ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL)
- {
- _scrollBarLeftCap = getImage("scrollBarLeftCap", _state);
- _scrollBarHorizontal = getImage("horizontalScrollBar", _state);
- _scrollBarRightCap = getImage("scrollBarRightCap", _state);
- GP_ASSERT(_scrollBarLeftCap && _scrollBarHorizontal && _scrollBarRightCap);
- _viewportClipBounds.height -= _scrollBarHorizontal->getRegion().height;
- }
- if ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL)
- {
- _scrollBarTopCap = getImage("scrollBarTopCap", _state);
- _scrollBarVertical = getImage("verticalScrollBar", _state);
- _scrollBarBottomCap = getImage("scrollBarBottomCap", _state);
- GP_ASSERT(_scrollBarTopCap && _scrollBarVertical && _scrollBarBottomCap);
-
- _viewportClipBounds.width -= _scrollBarVertical->getRegion().width;
- }
- GP_ASSERT(_layout);
- if (_scroll != SCROLL_NONE)
- {
- updateScroll();
- }
- else
- {
- _layout->update(this, Vector2::zero());
- }
- }
- void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, bool cleared, float targetHeight)
- {
- if (needsClear)
- {
- GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
- float clearY = targetHeight - _clearBounds.y - _clearBounds.height;
- GL_ASSERT( glScissor(_clearBounds.x, clearY, _clearBounds.width, _clearBounds.height) );
- Game::getInstance()->clear(Game::CLEAR_COLOR, Vector4::zero(), 1.0f, 0);
- GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
- needsClear = false;
- cleared = true;
- }
- else if (!cleared)
- {
- needsClear = true;
- }
- if (!_visible)
- {
- _dirty = false;
- return;
- }
- spriteBatch->start();
- Control::drawBorder(spriteBatch, clip);
- spriteBatch->finish();
- std::vector<Control*>::const_iterator it;
- Rectangle boundsUnion = Rectangle::empty();
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- Control* control = *it;
- GP_ASSERT(control);
- if (!needsClear || control->isDirty() || control->_clearBounds.intersects(boundsUnion))
- {
- control->draw(spriteBatch, _viewportClipBounds, needsClear, cleared, targetHeight);
- Rectangle::combine(control->_clearBounds, boundsUnion, &boundsUnion);
- }
- }
- if (_scroll != SCROLL_NONE && (_scrollBarOpacity > 0.0f))
- {
- // Draw scroll bars.
- Rectangle clipRegion(_viewportClipBounds);
- spriteBatch->start();
- if (_scrollBarBounds.height > 0 && ((_scroll & SCROLL_VERTICAL) == SCROLL_VERTICAL))
- {
- const Rectangle& topRegion = _scrollBarTopCap->getRegion();
- const Theme::UVs& topUVs = _scrollBarTopCap->getUVs();
- Vector4 topColor = _scrollBarTopCap->getColor();
- topColor.w *= _scrollBarOpacity * _opacity;
- const Rectangle& verticalRegion = _scrollBarVertical->getRegion();
- const Theme::UVs& verticalUVs = _scrollBarVertical->getUVs();
- Vector4 verticalColor = _scrollBarVertical->getColor();
- verticalColor.w *= _scrollBarOpacity * _opacity;
- const Rectangle& bottomRegion = _scrollBarBottomCap->getRegion();
- const Theme::UVs& bottomUVs = _scrollBarBottomCap->getUVs();
- Vector4 bottomColor = _scrollBarBottomCap->getColor();
- bottomColor.w *= _scrollBarOpacity * _opacity;
- clipRegion.width += verticalRegion.width;
- Rectangle bounds(_viewportBounds.x + _viewportBounds.width - verticalRegion.width, _viewportBounds.y + _scrollBarBounds.y, topRegion.width, topRegion.height);
- spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, topUVs.u1, topUVs.v1, topUVs.u2, topUVs.v2, topColor, clipRegion);
- bounds.y += topRegion.height;
- bounds.height = _scrollBarBounds.height - topRegion.height - bottomRegion.height;
- spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, verticalUVs.u1, verticalUVs.v1, verticalUVs.u2, verticalUVs.v2, verticalColor, clipRegion);
- bounds.y += bounds.height;
- bounds.height = bottomRegion.height;
- spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, bottomUVs.u1, bottomUVs.v1, bottomUVs.u2, bottomUVs.v2, bottomColor, clipRegion);
- }
- if (_scrollBarBounds.width > 0 && ((_scroll & SCROLL_HORIZONTAL) == SCROLL_HORIZONTAL))
- {
- const Rectangle& leftRegion = _scrollBarLeftCap->getRegion();
- const Theme::UVs& leftUVs = _scrollBarLeftCap->getUVs();
- Vector4 leftColor = _scrollBarLeftCap->getColor();
- leftColor.w *= _scrollBarOpacity * _opacity;
- const Rectangle& horizontalRegion = _scrollBarHorizontal->getRegion();
- const Theme::UVs& horizontalUVs = _scrollBarHorizontal->getUVs();
- Vector4 horizontalColor = _scrollBarHorizontal->getColor();
- horizontalColor.w *= _scrollBarOpacity * _opacity;
- const Rectangle& rightRegion = _scrollBarRightCap->getRegion();
- const Theme::UVs& rightUVs = _scrollBarRightCap->getUVs();
- Vector4 rightColor = _scrollBarRightCap->getColor();
- rightColor.w *= _scrollBarOpacity * _opacity;
- clipRegion.height += horizontalRegion.height;
-
- Rectangle bounds(_viewportBounds.x + _scrollBarBounds.x, _viewportBounds.y + _viewportBounds.height - horizontalRegion.height, leftRegion.width, leftRegion.height);
- spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, leftUVs.u1, leftUVs.v1, leftUVs.u2, leftUVs.v2, leftColor, clipRegion);
- bounds.x += leftRegion.width;
- bounds.width = _scrollBarBounds.width - leftRegion.width - rightRegion.width;
- spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, horizontalUVs.u1, horizontalUVs.v1, horizontalUVs.u2, horizontalUVs.v2, horizontalColor, clipRegion);
- bounds.x += bounds.width;
- bounds.width = rightRegion.width;
- spriteBatch->draw(bounds.x, bounds.y, bounds.width, bounds.height, rightUVs.u1, rightUVs.v1, rightUVs.u2, rightUVs.v2, rightColor, clipRegion);
- }
- spriteBatch->finish();
- if (_scrollingVelocity.isZero())
- {
- _dirty = false;
- }
- }
- else
- {
- _dirty = false;
- }
- }
- bool Container::isDirty()
- {
- if (_dirty)
- {
- return true;
- }
- else
- {
- std::vector<Control*>::const_iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- GP_ASSERT(*it);
- if ((*it)->isDirty())
- {
- return true;
- }
- }
- }
- return false;
- }
- bool Container::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
- {
- return pointerEvent(false, evt, x, y, (int)contactIndex);
- }
- bool Container::mouseEvent(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
- {
- return pointerEvent(true, evt, x, y, wheelDelta);
- }
- bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
- {
- // This event may run untrusted code by notifying listeners of events.
- // If the user calls exit() or otherwise releases this container, we
- // need to keep it alive until the method returns.
- addRef();
- bool eventConsumed = false;
- std::vector<Control*>::const_iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- Control* control = *it;
- GP_ASSERT(control);
- if (!control->isEnabled() || !control->isVisible())
- {
- continue;
- }
- if ((control->hasFocus() || control->getState() == ACTIVE) && control->keyEvent(evt, key))
- {
- eventConsumed |= true;
- break;
- }
- }
- switch (evt)
- {
- case Keyboard::KEY_PRESS:
- {
- if (!eventConsumed)
- {
- switch (key)
- {
- case Keyboard::KEY_TAB:
- _focusPressed |= NEXT;
- if (moveFocus(NEXT))
- eventConsumed |= true;
- break;
- case Keyboard::KEY_UP_ARROW:
- _focusPressed |= UP;
- if (moveFocus(UP))
- eventConsumed |= true;
- break;
- case Keyboard::KEY_DOWN_ARROW:
- _focusPressed |= DOWN;
- if (moveFocus(DOWN))
- eventConsumed |= true;
- break;
- case Keyboard::KEY_LEFT_ARROW:
- _focusPressed |= LEFT;
- if (moveFocus(LEFT))
- eventConsumed |= true;
- break;
- case Keyboard::KEY_RIGHT_ARROW:
- _focusPressed |= RIGHT;
- if (moveFocus(RIGHT))
- eventConsumed |= true;
- break;
- }
- }
- break;
- }
- case Keyboard::KEY_RELEASE:
- {
- switch (key)
- {
- case Keyboard::KEY_TAB:
- _focusPressed &= ~NEXT;
- eventConsumed |= true;
- break;
- case Keyboard::KEY_UP_ARROW:
- _focusPressed &= ~UP;
- eventConsumed |= true;
- break;
- case Keyboard::KEY_DOWN_ARROW:
- _focusPressed &= ~DOWN;
- eventConsumed |= true;
- break;
- case Keyboard::KEY_LEFT_ARROW:
- _focusPressed &= ~LEFT;
- eventConsumed |= true;
- break;
- case Keyboard::KEY_RIGHT_ARROW:
- _focusPressed &= ~RIGHT;
- eventConsumed |= true;
- break;
- }
- break;
- }
- }
- release();
- return eventConsumed;
- }
- void Container::guaranteeFocus(Control* inFocus)
- {
- std::vector<Control*>::const_iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- Control* control = *it;
- GP_ASSERT(control);
- if (control == inFocus)
- continue;
- if (control->isContainer())
- {
- ((Container*)control)->guaranteeFocus(inFocus);
- }
- else if (control->hasFocus())
- {
- control->setState(NORMAL);
- return;
- }
- }
- }
- bool Container::moveFocus(Direction direction, Control* outsideControl)
- {
- _direction = direction;
- Control* start = outsideControl;
- if (!start)
- {
- std::vector<Control*>::const_iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- Control* control = *it;
- GP_ASSERT(control);
- if (control->hasFocus())
- {
- start = control;
- break;
- }
- }
- }
- int focusIndex = 0;
- Control* next = NULL;
- if (start)
- {
- const Rectangle& startBounds = start->getAbsoluteBounds();
- Vector2 vStart, vNext;
- float distance = FLT_MAX;
- start->setState(Control::NORMAL);
- switch(direction)
- {
- case UP:
- vStart.set(startBounds.x + startBounds.width * 0.5f,
- startBounds.y);
- break;
- case DOWN:
- vStart.set(startBounds.x + startBounds.width * 0.5f,
- startBounds.bottom());
- break;
- case LEFT:
- vStart.set(startBounds.x,
- startBounds.y + startBounds.height * 0.5f);
- break;
- case RIGHT:
- vStart.set(startBounds.right(),
- startBounds.y + startBounds.height * 0.5f);
- break;
- case NEXT:
- break;
- }
- if (direction != NEXT)
- {
- std::vector<Control*>::const_iterator itt;
- for (itt = _controls.begin(); itt < _controls.end(); itt++)
- {
- Control* nextControl = *itt;
- if (nextControl == start || nextControl->getFocusIndex() < 0 ||
- !nextControl->isEnabled() || !nextControl->isVisible())
- {
- // Control is not focusable.
- continue;
- }
- const Rectangle& nextBounds = nextControl->getAbsoluteBounds();
- switch(direction)
- {
- case UP:
- vNext.set(nextBounds.x + nextBounds.width * 0.5f,
- nextBounds.bottom());
- if (vNext.y > vStart.y) continue;
- break;
- case DOWN:
- vNext.set(nextBounds.x + nextBounds.width * 0.5f,
- nextBounds.y);
- if (vNext.y < vStart.y) continue;
- break;
- case LEFT:
- vNext.set(nextBounds.right(),
- nextBounds.y + nextBounds.height * 0.5f);
- if (vNext.x > vStart.x) continue;
- break;
- case RIGHT:
- vNext.set(nextBounds.x,
- nextBounds.y + nextBounds.height * 0.5f);
- if (vNext.x < vStart.x) continue;
- break;
- }
- float nextDistance = vStart.distance(vNext);
- if (abs(nextDistance) < distance)
- {
- distance = nextDistance;
- next = nextControl;
- }
- }
- }
- if (!next)
- {
- // Check for controls in the given direction in our parent container.
- if (direction != NEXT && !outsideControl && _parent && _parent->moveFocus(direction, start))
- {
- setState(NORMAL);
- _focusChangeRepeat = false;
- _focusPressed = 0;
- return true;
- }
-
- // No control is in the given direction. Move to the next control in the focus order.
- int focusDelta;
- switch(direction)
- {
- case UP:
- case LEFT:
- focusDelta = -1;
- break;
- case DOWN:
- case RIGHT:
- case NEXT:
- focusDelta = 1;
- break;
- }
- // Find the index to search for.
- if (outsideControl)
- {
- focusIndex = outsideControl->_parent->getFocusIndex() + focusDelta;
- }
- else
- {
- focusIndex = start->getFocusIndex() + focusDelta;
- }
- if (focusIndex > _focusIndexMax)
- {
- if (direction == NEXT && !outsideControl && _parent && _parent->moveFocus(direction, start))
- {
- setState(NORMAL);
- _focusChangeRepeat = false;
- _focusPressed = 0;
- return true;
- }
- focusIndex = 0;
- }
- else if (focusIndex < 0)
- {
- focusIndex = _focusIndexMax;
- }
- }
- }
- if (!next)
- {
- std::vector<Control*>::const_iterator itt;
- for (itt = _controls.begin(); itt < _controls.end(); itt++)
- {
- Control* nextControl = *itt;
- if (nextControl->getFocusIndex() == focusIndex &&
- nextControl->isEnabled() && nextControl->isVisible())
- {
- next = nextControl;
- break;
- }
- }
- }
- // If we haven't found next by now, then there are no focusable controls in this container.
- if (next)
- {
- next->setState(Control::FOCUS);
- _dirty = true;
- if (next->isContainer())
- {
- if ((direction == NEXT && ((Container*)next)->moveFocus(direction)) ||
- ((Container*)next)->moveFocus(direction, start))
- {
- _focusChangeRepeat = false;
- _focusPressed = 0;
- return true;
- }
- }
- // If the next control is not fully visible, scroll the container so that it is.
- const Rectangle& bounds = next->getBounds();
- if (bounds.x < _scrollPosition.x)
- {
- // Control is to the left of the scrolled viewport.
- _scrollPosition.x = -bounds.x;
- }
- else if (bounds.x + bounds.width > _scrollPosition.x + _viewportBounds.width)
- {
- // Control is off to the right.
- _scrollPosition.x = -(bounds.x + bounds.width - _viewportBounds.width);
- }
- if (bounds.y < _viewportBounds.y - _scrollPosition.y)
- {
- // Control is above the viewport.
- _scrollPosition.y = -bounds.y;
- }
- else if (bounds.y + bounds.height > _viewportBounds.height - _scrollPosition.y)
- {
- // Control is below the viewport.
- _scrollPosition.y = -(bounds.y + bounds.height - _viewportBounds.height);
- }
- if (outsideControl && outsideControl->_parent)
- {
- _focusPressed = outsideControl->_parent->_focusPressed;
- _focusChangeCount = outsideControl->_parent->_focusChangeCount;
- _focusChangeRepeatDelay = outsideControl->_parent->_focusChangeRepeatDelay;
- outsideControl->_parent->guaranteeFocus(next);
- }
- _focusChangeStartTime = Game::getAbsoluteTime();
- _focusChangeRepeat = true;
- addRef();
- Game::getInstance()->schedule(_focusChangeRepeatDelay, this);
- return true;
- }
- return false;
- }
- void Container::timeEvent(long timeDiff, void* cookie)
- {
- double time = Game::getAbsoluteTime();
- if (_focusChangeRepeat && hasFocus() && _focusPressed &&
- abs(time - timeDiff - _focusChangeRepeatDelay - _focusChangeStartTime) < 50)
- {
- ++_focusChangeCount;
- if (_focusChangeCount == 5)
- {
- _focusChangeRepeatDelay *= 0.5;
- }
- moveFocus(_direction);
- }
- else
- {
- _focusChangeCount = 0;
- _focusChangeRepeatDelay = FOCUS_CHANGE_REPEAT_DELAY;
- }
- release();
- }
- void Container::startScrolling(float x, float y, bool resetTime)
- {
- _scrollingVelocity.set(-x, y);
- _scrolling = true;
- _scrollBarOpacity = 1.0f;
- _dirty = true;
- if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
- {
- _scrollBarOpacityClip->stop();
- _scrollBarOpacityClip = NULL;
- }
- if (resetTime)
- {
- _lastFrameTime = Game::getGameTime();
- }
- }
- void Container::stopScrolling()
- {
- _scrollingVelocity.set(0, 0);
- _scrolling = false;
- _dirty = true;
- }
- bool Container::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
- {
- addRef();
- bool eventConsumed = false;
- // Pass the event to any control that is active or in focus.
- std::vector<Control*>::const_iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- Control* control = *it;
- GP_ASSERT(control);
- if (control->hasFocus() || control->getState() == Control::ACTIVE)
- {
- eventConsumed |= control->gamepadEvent(evt, gamepad, analogIndex);
- break;
- }
- }
- // First check if a selection button is down.
- if (!_selectButtonDown)
- {
- if (gamepad->isButtonDown(Gamepad::BUTTON_A) ||
- gamepad->isButtonDown(Gamepad::BUTTON_X))
- {
- _selectButtonDown = true;
- _focusChangeRepeat = false;
- eventConsumed |= _consumeInputEvents;
- }
- }
- else
- {
- if (!gamepad->isButtonDown(Gamepad::BUTTON_A) &&
- !gamepad->isButtonDown(Gamepad::BUTTON_X))
- {
- _selectButtonDown = false;
- }
- }
- Vector2 joystick;
- gamepad->getJoystickValues(analogIndex, &joystick);
- // Don't allow focus changes or scrolling while a selection button is down.
- if (!_selectButtonDown && !eventConsumed)
- {
- switch (evt)
- {
- case Gamepad::BUTTON_EVENT:
- {
- // Shift focus forward or backward when the DPad is used.
- if (!(_focusPressed & DOWN) &&
- gamepad->isButtonDown(Gamepad::BUTTON_DOWN))
- {
- _focusPressed |= DOWN;
- eventConsumed = true;
- if (moveFocus(DOWN))
- break;
- else
- startScrolling(0, -GAMEPAD_SCROLL_SPEED);
- }
-
- if (!(_focusPressed & RIGHT) &&
- gamepad->isButtonDown(Gamepad::BUTTON_RIGHT))
- {
- _focusPressed |= RIGHT;
- eventConsumed = true;
- if (moveFocus(RIGHT))
- break;
- else
- startScrolling(GAMEPAD_SCROLL_SPEED, 0);
- }
- if (!(_focusPressed & UP) &&
- gamepad->isButtonDown(Gamepad::BUTTON_UP))
- {
- _focusPressed |= UP;
- eventConsumed = true;
- if (moveFocus(UP))
- break;
- else
- startScrolling(0, GAMEPAD_SCROLL_SPEED);
- }
- if (!(_focusPressed & LEFT) &&
- gamepad->isButtonDown(Gamepad::BUTTON_LEFT))
- {
- _focusPressed |= LEFT;
- eventConsumed = true;
- if (moveFocus(LEFT))
- break;
- else
- startScrolling(-GAMEPAD_SCROLL_SPEED, 0);
- }
- break;
- }
- case Gamepad::JOYSTICK_EVENT:
- {
- switch (analogIndex)
- {
- case 0:
- // The left analog stick can be used in the same way as the DPad.
- eventConsumed = true;
- if (!(_focusPressed & RIGHT) &&
- joystick.x > JOYSTICK_THRESHOLD)
- {
- _focusPressed |= RIGHT;
- if (moveFocus(RIGHT))
- break;
- else
- startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, 0);
- }
- if (!(_focusPressed & DOWN) &&
- joystick.y < -JOYSTICK_THRESHOLD)
- {
- _focusPressed |= DOWN;
- if (moveFocus(DOWN))
- break;
- else
- startScrolling(0, GAMEPAD_SCROLL_SPEED * joystick.y);
- }
- if (!(_focusPressed & LEFT) &&
- joystick.x < -JOYSTICK_THRESHOLD)
- {
- _focusPressed |= LEFT;
- if (moveFocus(LEFT))
- break;
- else
- startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, 0);
- }
-
- if (!(_focusPressed & UP) &&
- joystick.y > JOYSTICK_THRESHOLD)
- {
- _focusPressed |= UP;
- if (moveFocus(UP))
- break;
- else
- startScrolling(0, GAMEPAD_SCROLL_SPEED * joystick.y);
- }
- break;
- case 1:
- // The right analog stick can be used to scroll.
- if (_scroll != SCROLL_NONE)
- {
- if (_scrolling)
- {
- if (joystick.isZero())
- {
- stopScrolling();
- }
- else
- {
- startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y, false);
- }
- }
- else
- {
- startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y);
- }
- release();
- return _consumeInputEvents;
- }
- break;
- }
- }
- }
- }
- if ((evt == Gamepad::BUTTON_EVENT || evt == Gamepad::JOYSTICK_EVENT) &&
- analogIndex == 0)
- {
- if ((_focusPressed & DOWN) &&
- !gamepad->isButtonDown(Gamepad::BUTTON_DOWN) &&
- joystick.y > -JOYSTICK_THRESHOLD)
- {
- _focusPressed &= ~DOWN;
- eventConsumed = true;
- }
- if ((_focusPressed & RIGHT) &&
- !gamepad->isButtonDown(Gamepad::BUTTON_RIGHT) &&
- joystick.x < JOYSTICK_THRESHOLD)
- {
- _focusPressed &= ~RIGHT;
- eventConsumed = true;
- }
-
- if ((_focusPressed & UP) &&
- !gamepad->isButtonDown(Gamepad::BUTTON_UP) &&
- joystick.y < JOYSTICK_THRESHOLD)
- {
- _focusPressed &= ~UP;
- eventConsumed = true;
- }
- if ((_focusPressed & LEFT) &&
- !gamepad->isButtonDown(Gamepad::BUTTON_LEFT) &&
- joystick.x > -JOYSTICK_THRESHOLD)
- {
- _focusPressed &= ~LEFT;
- eventConsumed = true;
- }
- }
- if (!_focusPressed && _scrolling)
- {
- stopScrolling();
- }
- release();
- return eventConsumed;
- }
- bool Container::isContainer() const
- {
- return true;
- }
- Layout::Type Container::getLayoutType(const char* layoutString)
- {
- if (!layoutString)
- {
- return Layout::LAYOUT_ABSOLUTE;
- }
- std::string layoutName(layoutString);
- std::transform(layoutName.begin(), layoutName.end(), layoutName.begin(), (int(*)(int))toupper);
- if (layoutName == "LAYOUT_ABSOLUTE")
- {
- return Layout::LAYOUT_ABSOLUTE;
- }
- else if (layoutName == "LAYOUT_VERTICAL")
- {
- return Layout::LAYOUT_VERTICAL;
- }
- else if (layoutName == "LAYOUT_FLOW")
- {
- return Layout::LAYOUT_FLOW;
- }
- else
- {
- // Default.
- return Layout::LAYOUT_ABSOLUTE;
- }
- }
- void Container::updateScroll()
- {
- if (!_initializedWithScroll)
- {
- _initializedWithScroll = true;
- _layout->update(this, _scrollPosition);
- }
- // Update time.
- if (!_lastFrameTime)
- {
- _lastFrameTime = Game::getGameTime();
- }
- double frameTime = Game::getGameTime();
- float elapsedTime = (float)(frameTime - _lastFrameTime);
- _lastFrameTime = frameTime;
- const Theme::Border& containerBorder = getBorder(_state);
- const Theme::Padding& containerPadding = getPadding();
- // Calculate total width and height.
- _totalWidth = _totalHeight = 0.0f;
- std::vector<Control*> controls = getControls();
- for (size_t i = 0, controlsCount = controls.size(); i < controlsCount; i++)
- {
- Control* control = controls.at(i);
- const Rectangle& bounds = control->getBounds();
- const Theme::Margin& margin = control->getMargin();
- float newWidth = bounds.x + bounds.width + margin.right;
- if (newWidth > _totalWidth)
- {
- _totalWidth = newWidth;
- }
- float newHeight = bounds.y + bounds.height + margin.bottom;
- if (newHeight > _totalHeight)
- {
- _totalHeight = newHeight;
- }
- }
- float vWidth = getImageRegion("verticalScrollBar", _state).width;
- float hHeight = getImageRegion("horizontalScrollBar", _state).height;
- float clipWidth = _bounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right - vWidth;
- float clipHeight = _bounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom - hHeight;
- // Apply and dampen inertia.
- if (!_scrollingVelocity.isZero())
- {
- // Calculate the time passed since last update.
- float elapsedSecs = (float)elapsedTime * 0.001f;
- _scrollPosition.x += _scrollingVelocity.x * elapsedSecs;
- _scrollPosition.y += _scrollingVelocity.y * elapsedSecs;
- if (!_scrolling)
- {
- float dampening = 1.0f - _scrollingFriction * SCROLL_FRICTION_FACTOR * elapsedSecs;
- _scrollingVelocity.x *= dampening;
- _scrollingVelocity.y *= dampening;
- if (fabs(_scrollingVelocity.x) < 100.0f)
- _scrollingVelocity.x = 0.0f;
- if (fabs(_scrollingVelocity.y) < 100.0f)
- _scrollingVelocity.y = 0.0f;
- }
- }
- // Stop scrolling when the far edge is reached.
- if (-_scrollPosition.x > _totalWidth - clipWidth)
- {
- _scrollPosition.x = -(_totalWidth - clipWidth);
- _scrollingVelocity.x = 0;
- }
-
- if (-_scrollPosition.y > _totalHeight - clipHeight)
- {
- _scrollPosition.y = -(_totalHeight - clipHeight);
- _scrollingVelocity.y = 0;
- }
- if (_scrollPosition.x > 0)
- {
- _scrollPosition.x = 0;
- _scrollingVelocity.x = 0;
- }
- if (_scrollPosition.y > 0)
- {
- _scrollPosition.y = 0;
- _scrollingVelocity.y = 0;
- }
- float scrollWidth = 0;
- if (clipWidth < _totalWidth)
- scrollWidth = (clipWidth / _totalWidth) * clipWidth;
- float scrollHeight = 0;
- if (clipHeight < _totalHeight)
- scrollHeight = (clipHeight / _totalHeight) * clipHeight;
- _scrollBarBounds.set(((-_scrollPosition.x) / _totalWidth) * clipWidth,
- ((-_scrollPosition.y) / _totalHeight) * clipHeight,
- scrollWidth, scrollHeight);
- // If scroll velocity is 0 and scrollbars are not always visible, trigger fade-out animation.
- if (!_scrolling && _scrollingVelocity.isZero() && _scrollBarsAutoHide && _scrollBarOpacity == 1.0f)
- {
- float to = 0;
- _scrollBarOpacity = 0.99f;
- if (!_scrollBarOpacityClip)
- {
- Animation* animation = createAnimationFromTo("scrollbar-fade-out", ANIMATE_SCROLLBAR_OPACITY, &_scrollBarOpacity, &to, Curve::QUADRATIC_IN_OUT, 500L);
- _scrollBarOpacityClip = animation->getClip();
- }
- _scrollBarOpacityClip->play();
- }
- // Position controls within scroll area.
- _layout->update(this, _scrollPosition);
- }
- void Container::sortControls()
- {
- if (_layout->getType() == Layout::LAYOUT_ABSOLUTE)
- {
- std::sort(_controls.begin(), _controls.end(), &sortControlsByZOrder);
- }
- }
- bool Container::touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
- {
- switch(evt)
- {
- case Touch::TOUCH_PRESS:
- if (_contactIndex == INVALID_CONTACT_INDEX)
- {
- _contactIndex = (int) contactIndex;
- _scrollingLastX = _scrollingFirstX = _scrollingVeryFirstX = x;
- _scrollingLastY = _scrollingFirstY = _scrollingVeryFirstY = y;
- _scrollingVelocity.set(0, 0);
- _scrolling = true;
- _scrollingStartTimeX = _scrollingStartTimeY = 0;
- if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
- {
- _scrollBarOpacityClip->stop();
- _scrollBarOpacityClip = NULL;
- }
- _scrollBarOpacity = 1.0f;
- _dirty = true;
- return _consumeInputEvents;
- }
- break;
- case Touch::TOUCH_MOVE:
- if (_scrolling && _contactIndex == (int) contactIndex)
- {
- double gameTime = Game::getAbsoluteTime();
- // Calculate the latest movement delta for the next update to use.
- int vx = x - _scrollingLastX;
- int vy = y - _scrollingLastY;
- if (_scrollingMouseVertically)
- {
- float yRatio = _totalHeight / _absoluteBounds.height;
- vy *= yRatio;
- _scrollingVelocity.set(0, -vy);
- _scrollPosition.y -= vy;
- }
- else if (_scrollingMouseHorizontally)
- {
- float xRatio = _totalWidth / _absoluteBounds.width;
- vx *= xRatio;
- _scrollingVelocity.set(-vx, 0);
- _scrollPosition.x -= vx;
- }
- else
- {
- _scrollingVelocity.set(vx, vy);
- _scrollPosition.x += vx;
- _scrollPosition.y += vy;
- }
- _scrollingLastX = x;
- _scrollingLastY = y;
- // If the user changes direction, reset the start time and position.
- bool goingRight = (vx > 0);
- if (goingRight != _scrollingRight)
- {
- _scrollingFirstX = x;
- _scrollingRight = goingRight;
- _scrollingStartTimeX = gameTime;
- }
- bool goingDown = (vy > 0);
- if (goingDown != _scrollingDown)
- {
- _scrollingFirstY = y;
- _scrollingDown = goingDown;
- _scrollingStartTimeY = gameTime;
- }
- if (!_scrollingStartTimeX)
- _scrollingStartTimeX = gameTime;
- if (!_scrollingStartTimeY)
- _scrollingStartTimeY = gameTime;
- _scrollingLastTime = gameTime;
- _dirty = true;
- return _consumeInputEvents;
- }
- break;
- case Touch::TOUCH_RELEASE:
- if (_contactIndex == (int) contactIndex)
- {
- _contactIndex = INVALID_CONTACT_INDEX;
- _scrolling = false;
- double gameTime = Game::getAbsoluteTime();
- float timeSinceLastMove = (float)(gameTime - _scrollingLastTime);
- if (timeSinceLastMove > SCROLL_INERTIA_DELAY)
- {
- _scrollingVelocity.set(0, 0);
- _scrollingMouseVertically = _scrollingMouseHorizontally = false;
- _dirty = true;
- return _consumeInputEvents;
- }
- int dx = _scrollingLastX - _scrollingFirstX;
- int dy = _scrollingLastY - _scrollingFirstY;
- float timeTakenX = (float)(gameTime - _scrollingStartTimeX);
- float elapsedSecsX = timeTakenX * 0.001f;
- float timeTakenY = (float)(gameTime - _scrollingStartTimeY);
- float elapsedSecsY = timeTakenY * 0.001f;
- float vx = dx;
- float vy = dy;
- if (elapsedSecsX > 0)
- vx = (float)dx / elapsedSecsX;
- if (elapsedSecsY > 0)
- vy = (float)dy / elapsedSecsY;
- if (_scrollingMouseVertically)
- {
- float yRatio = _totalHeight / _absoluteBounds.height;
- vy *= yRatio;
- _scrollingVelocity.set(0, -vy);
- }
- else if (_scrollingMouseHorizontally)
- {
- float xRatio = _totalWidth / _absoluteBounds.width;
- vx *= xRatio;
- _scrollingVelocity.set(-vx, 0);
- }
- else
- {
- _scrollingVelocity.set(vx, vy);
- }
- _scrollingMouseVertically = _scrollingMouseHorizontally = false;
- _dirty = true;
- return _consumeInputEvents;
- }
- break;
- }
- return false;
- }
- bool Container::mouseEventScroll(Mouse::MouseEvent evt, int x, int y, int wheelDelta)
- {
- switch(evt)
- {
- case Mouse::MOUSE_PRESS_LEFT_BUTTON:
- {
- if (_scrollBarVertical)
- {
- float vWidth = _scrollBarVertical->getRegion().width;
- Rectangle vBounds(_viewportBounds.x + _viewportBounds.width - vWidth,
- _scrollBarBounds.y,
- vWidth, _scrollBarBounds.height);
- if (x + _viewportBounds.x >= vBounds.x &&
- x + _viewportBounds.x <= vBounds.x + vBounds.width)
- {
- // Then we're within the horizontal bounds of the vertical scrollbar.
- // We want to either jump up or down, or drag the scrollbar itself.
- if (y < vBounds.y)
- {
- _scrollPosition.y += _totalHeight / 5.0f;
- }
- else if (y > vBounds.y + vBounds.height)
- {
- _scrollPosition.y -= _totalHeight / 5.0f;
- }
- else
- {
- _scrollingMouseVertically = true;
- }
- }
- }
-
- if (_scrollBarHorizontal)
- {
- float hHeight = _scrollBarHorizontal->getRegion().height;
- Rectangle hBounds(_scrollBarBounds.x,
- _viewportBounds.y + _viewportBounds.height - hHeight,
- _scrollBarBounds.width, hHeight);
-
- if (y + _viewportBounds.y >= hBounds.y &&
- y + _viewportBounds.y <= hBounds.y + hBounds.height)
- {
- // We're within the vertical bounds of the horizontal scrollbar.
- if (x < hBounds.x)
- _scrollPosition.x += _totalWidth / 5.0f;
- else if (x > hBounds.x + hBounds.width)
- _scrollPosition.x -= _totalWidth / 5.0f;
- else
- _scrollingMouseHorizontally = true;
- }
- }
- return touchEventScroll(Touch::TOUCH_PRESS, x, y, 0);
- }
- case Mouse::MOUSE_MOVE:
- return touchEventScroll(Touch::TOUCH_MOVE, x, y, 0);
- case Mouse::MOUSE_RELEASE_LEFT_BUTTON:
- return touchEventScroll(Touch::TOUCH_RELEASE, x, y, 0);
- case Mouse::MOUSE_WHEEL:
- if ((_state == HOVER && (!_scrollWheelRequiresFocus || _previousState == FOCUS)) ||
- _state == FOCUS && _scrollWheelRequiresFocus)
- {
- if (_scrollingVelocity.isZero())
- {
- _lastFrameTime = Game::getGameTime();
- }
- _scrolling = _scrollingMouseVertically = _scrollingMouseHorizontally = false;
- _scrollingVelocity.y += _scrollWheelSpeed * wheelDelta;
- if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
- {
- _scrollBarOpacityClip->stop();
- _scrollBarOpacityClip = NULL;
- }
- _scrollBarOpacity = 1.0f;
- _dirty = true;
- return _consumeInputEvents;
- }
- break;
- }
- return false;
- }
- bool Container::inContact()
- {
- for (int i = 0; i < MAX_CONTACT_INDICES; ++i)
- {
- if (_contactIndices[i])
- return true;
- }
- return false;
- }
- bool Container::pointerEvent(bool mouse, char evt, int x, int y, int data)
- {
- if (!isEnabled() || !isVisible())
- {
- return false;
- }
- // This event may run untrusted code by notifying listeners of events.
- // If the user calls exit() or otherwise releases this container, we
- // need to keep it alive until the method returns.
- addRef();
- bool eventConsumed = false;
- const Theme::Border& border = getBorder(_state);
- const Theme::Padding& padding = getPadding();
- float xPos = border.left + padding.left;
- float yPos = border.top + padding.top;
- Vector2* offset = NULL;
- if (_scroll != SCROLL_NONE)
- {
- offset = &_scrollPosition;
- }
- std::vector<Control*>::const_iterator it;
- for (it = _controls.begin(); it < _controls.end(); it++)
- {
- Control* control = *it;
- GP_ASSERT(control);
- if (!control->isEnabled() || !control->isVisible())
- {
- continue;
- }
- const Rectangle& bounds = control->getBounds();
- float boundsX = bounds.x;
- float boundsY = bounds.y;
- if (offset)
- {
- boundsX += offset->x;
- boundsY += offset->y;
- }
- Control::State currentState = control->getState();
- if ((currentState != Control::NORMAL) ||
- ((evt == Touch::TOUCH_PRESS ||
- evt == Mouse::MOUSE_PRESS_LEFT_BUTTON ||
- evt == Mouse::MOUSE_PRESS_MIDDLE_BUTTON ||
- evt == Mouse::MOUSE_PRESS_RIGHT_BUTTON ||
- evt == Mouse::MOUSE_MOVE ||
- evt == Mouse::MOUSE_WHEEL) &&
- x >= xPos + boundsX &&
- x <= xPos + boundsX + bounds.width &&
- y >= yPos + boundsY &&
- y <= yPos + boundsY + bounds.height))
- {
- // Pass on the event's clip relative to the control.
- if (mouse)
- eventConsumed |= control->mouseEvent((Mouse::MouseEvent)evt, x - xPos - boundsX, y - yPos - boundsY, data);
- else
- eventConsumed |= control->touchEvent((Touch::TouchEvent)evt, x - xPos - boundsX, y - yPos - boundsY, (unsigned int)data);
- }
- }
- if (!isEnabled() || !isVisible())
- {
- _contactIndex = INVALID_CONTACT_INDEX;
- clearContacts();
- _scrolling = false;
- _scrollingMouseVertically = _scrollingMouseHorizontally = false;
- release();
- return (_consumeInputEvents | eventConsumed);
- }
- bool withinClipBounds = (x > _clipBounds.x && x <= _clipBounds.x + _clipBounds.width &&
- y > _clipBounds.y && y <= _clipBounds.y + _clipBounds.height);
- switch (evt)
- {
- case Touch::TOUCH_PRESS:
- if (withinClipBounds)
- {
- setState(Control::ACTIVE);
- }
- else if (!inContact())
- {
- setState(Control::NORMAL);
- _contactIndex = INVALID_CONTACT_INDEX;
- release();
- return false;
- }
- if (!mouse)
- _contactIndices[data] = true;
- break;
- case Mouse::MOUSE_MOVE:
- if (_state != ACTIVE)
- {
- if (_state != HOVER && withinClipBounds)
- {
- _previousState = _state;
- setState(HOVER);
- notifyListeners(Control::Listener::ENTER);
- }
- else if (_state == HOVER && !withinClipBounds)
- {
- setState(_previousState);
- notifyListeners(Control::Listener::LEAVE);
- }
- else if (_state != HOVER)
- {
- release();
- return false;
- }
- }
- break;
- case Mouse::MOUSE_WHEEL:
- if (!withinClipBounds && !_scrollWheelRequiresFocus)
- {
- release();
- return false;
- }
- break;
- case Touch::TOUCH_RELEASE:
- if (!mouse)
- _contactIndices[data] = false;
- if (!inContact())
- {
- if (_state == ACTIVE && withinClipBounds)
- {
- setState(FOCUS);
- }
- else
- {
- setState(NORMAL);
- }
- }
- break;
- }
- if (!eventConsumed && _scroll != SCROLL_NONE &&
- (evt != Touch::TOUCH_PRESS || withinClipBounds))
- {
- if ((mouse && mouseEventScroll((Mouse::MouseEvent)evt, x - xPos, y - yPos, data)) ||
- (!mouse && touchEventScroll((Touch::TouchEvent)evt, x - xPos, y - yPos, (unsigned int)data)))
- {
- eventConsumed = true;
- }
- }
- release();
- return (_consumeInputEvents | eventConsumed);
- }
- Container::Scroll Container::getScroll(const char* scroll)
- {
- if (!scroll)
- return Container::SCROLL_NONE;
- if (strcmp(scroll, "SCROLL_NONE") == 0)
- {
- return Container::SCROLL_NONE;
- }
- else if (strcmp(scroll, "SCROLL_HORIZONTAL") == 0)
- {
- return Container::SCROLL_HORIZONTAL;
- }
- else if (strcmp(scroll, "SCROLL_VERTICAL") == 0)
- {
- return Container::SCROLL_VERTICAL;
- }
- else if (strcmp(scroll, "SCROLL_BOTH") == 0)
- {
- return Container::SCROLL_BOTH;
- }
- else
- {
- GP_ERROR("Failed to get corresponding scroll state for unsupported value '%s'.", scroll);
- }
- return Container::SCROLL_NONE;
- }
- float Container::getScrollingFriction() const
- {
- return _scrollingFriction;
- }
- void Container::setScrollingFriction(float friction)
- {
- _scrollingFriction = friction;
- }
- float Container::getScrollWheelSpeed() const
- {
- return _scrollWheelSpeed;
- }
- void Container::setScrollWheelSpeed(float speed)
- {
- _scrollWheelSpeed = speed;
- }
- static bool sortControlsByZOrder(Control* c1, Control* c2)
- {
- if (c1->getZIndex() < c2->getZIndex())
- return true;
- return false;
- }
- unsigned int Container::getAnimationPropertyComponentCount(int propertyId) const
- {
- switch(propertyId)
- {
- case ANIMATE_SCROLLBAR_OPACITY:
- return 1;
- default:
- return Control::getAnimationPropertyComponentCount(propertyId);
- }
- }
- void Container::getAnimationPropertyValue(int propertyId, AnimationValue* value)
- {
- GP_ASSERT(value);
- switch(propertyId)
- {
- case ANIMATE_SCROLLBAR_OPACITY:
- value->setFloat(0, _scrollBarOpacity);
- break;
- default:
- Control::getAnimationPropertyValue(propertyId, value);
- break;
- }
- }
- void Container::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
- {
- GP_ASSERT(value);
- switch(propertyId)
- {
- case ANIMATE_SCROLLBAR_OPACITY:
- _scrollBarOpacity = Curve::lerp(blendWeight, _opacity, value->getFloat(0));
- _dirty = true;
- break;
- default:
- Control::setAnimationPropertyValue(propertyId, value, blendWeight);
- break;
- }
- }
- }
|