| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- #include "BsGUIWidget.h"
- #include "BsGUIManager.h"
- #include "BsGUISkin.h"
- #include "BsGUILabel.h"
- #include "BsGUIMouseEvent.h"
- #include "BsGUIArea.h"
- #include "BsCoreApplication.h"
- #include "BsCoreThreadAccessor.h"
- #include "BsMaterial.h"
- #include "BsPass.h"
- #include "BsMesh.h"
- #include "BsVector2I.h"
- #include "BsOverlayManager.h"
- #include "BsCamera.h"
- #include "BsViewport.h"
- #include "BsSceneObject.h"
- #include "BsRenderWindow.h"
- namespace BansheeEngine
- {
- GUISkin GUIWidget::DefaultSkin;
- GUIWidget::GUIWidget(const HSceneObject& parent, Viewport* target)
- :Component(parent), mSkin(nullptr), mWidgetIsDirty(false), mTarget(nullptr), mDepth(0)
- {
- setName("GUIWidget");
- mLastFramePosition = SO()->getWorldPosition();
- mLastFrameRotation = SO()->getWorldRotation();
- mLastFrameScale = SO()->getWorldScale();
- assert(target != nullptr);
- mTarget = target;
- mOwnerTargetResizedConn = mTarget->getTarget()->onResized.connect(std::bind(&GUIWidget::ownerTargetResized, this));
- GUIManager::instance().registerWidget(this);
- }
- GUIWidget::~GUIWidget()
- { }
- void GUIWidget::onDestroyed()
- {
- if (mTarget != nullptr)
- {
- GUIManager::instance().unregisterWidget(this);
- mOwnerTargetResizedConn.disconnect();
- }
- // Iterate over all elements in this way because each
- // GUIElement::destroy call internally unregisters the element
- // from the widget, and modifies the mElements array
- while (mElements.size() > 0)
- {
- GUIElement::destroy(mElements[0]);
- }
- for (auto& area : mAreas)
- {
- GUIArea::destroyInternal(area);
- }
- mElements.clear();
- }
- void GUIWidget::update()
- {
- // If the widgets parent scene object moved, we need to mark it as dirty
- // as the GUIManager batching relies on object positions, so it needs to be updated.
- const float diffEpsilon = 0.0001f;
- Vector3 position = SO()->getWorldPosition();
- Quaternion rotation = SO()->getWorldRotation();
- Vector3 scale = SO()->getWorldScale();
- if(!mWidgetIsDirty)
- {
- Vector3 posDiff = mLastFramePosition - position;
- if(Math::abs(posDiff.x) > diffEpsilon || Math::abs(posDiff.y) > diffEpsilon || Math::abs(posDiff.z) > diffEpsilon)
- {
- mWidgetIsDirty = true;
- }
- else
- {
- Quaternion rotDiff = mLastFrameRotation - rotation;
- if(Math::abs(rotDiff.x) > diffEpsilon || Math::abs(rotDiff.y) > diffEpsilon ||
- Math::abs(rotDiff.z) > diffEpsilon || Math::abs(rotDiff.w) > diffEpsilon)
- {
- mWidgetIsDirty = true;
- }
- else
- {
- Vector3 scaleDiff = mLastFrameScale - scale;
- if(Math::abs(scaleDiff.x) > diffEpsilon || Math::abs(scaleDiff.y) > diffEpsilon || Math::abs(scaleDiff.z) > diffEpsilon)
- {
- mWidgetIsDirty = true;
- }
- }
- }
- }
- mLastFramePosition = position;
- mLastFrameRotation = rotation;
- mLastFrameScale = scale;
- }
- void GUIWidget::_updateLayout()
- {
- for(auto& area : mAreas)
- {
- area->_update();
- }
- }
- bool GUIWidget::_mouseEvent(GUIElement* element, const GUIMouseEvent& ev)
- {
- return element->mouseEvent(ev);
- }
- bool GUIWidget::_textInputEvent(GUIElement* element, const GUITextInputEvent& ev)
- {
- return element->textInputEvent(ev);
- }
- bool GUIWidget::_commandEvent(GUIElement* element, const GUICommandEvent& ev)
- {
- return element->commandEvent(ev);
- }
- bool GUIWidget::_virtualButtonEvent(GUIElement* element, const GUIVirtualButtonEvent& ev)
- {
- return element->virtualButtonEvent(ev);
- }
- void GUIWidget::registerElement(GUIElement* elem)
- {
- assert(elem != nullptr);
- mElements.push_back(elem);
- mWidgetIsDirty = true;
- }
- void GUIWidget::unregisterElement(GUIElement* elem)
- {
- assert(elem != nullptr);
- auto iterFind = std::find(begin(mElements), end(mElements), elem);
- if (iterFind != mElements.end())
- {
- mElements.erase(iterFind);
- mWidgetIsDirty = true;
- }
- }
- void GUIWidget::registerArea(GUIArea* area)
- {
- assert(area != nullptr);
- mAreas.push_back(area);
- mWidgetIsDirty = true;
- }
- void GUIWidget::unregisterArea(GUIArea* area)
- {
- assert(area != nullptr);
- auto iterFind = std::find(begin(mAreas), end(mAreas), area);
- if(iterFind == mAreas.end())
- BS_EXCEPT(InvalidParametersException, "Cannot unregister an area that is not registered on this widget.");
- mAreas.erase(iterFind);
- mWidgetIsDirty = true;
- }
- void GUIWidget::setSkin(const GUISkin& skin)
- {
- mSkin = &skin;
- for(auto& element : mElements)
- element->_refreshStyle();
- }
- const GUISkin& GUIWidget::getSkin() const
- {
- if(mSkin != nullptr)
- return *mSkin;
- else
- return DefaultSkin;
- }
- bool GUIWidget::isDirty(bool cleanIfDirty)
- {
- if(cleanIfDirty)
- {
- bool dirty = mWidgetIsDirty;
- mWidgetIsDirty = false;
- for(auto& elem : mElements)
- {
- if(elem->_isContentDirty())
- {
- dirty = true;
- elem->updateRenderElements();
- }
- if(elem->_isMeshDirty())
- {
- dirty = true;
- elem->_markAsClean();
- }
- }
- if(dirty)
- updateBounds();
- return dirty;
- }
- else
- {
- if(mWidgetIsDirty)
- return true;
- for(auto& elem : mElements)
- {
- if(elem->_isContentDirty() || elem->_isMeshDirty())
- {
- return true;
- }
- }
- return false;
- }
- }
- bool GUIWidget::inBounds(const Vector2I& position) const
- {
- // Technically GUI widget bounds can be larger than the viewport, so make sure we clip to viewport first
- if(!getTarget()->getArea().contains(position))
- return false;
- const Matrix4& worldTfrm = SO()->getWorldTfrm();
- Vector3 vecPos((float)position.x, (float)position.y, 0.0f);
- vecPos = worldTfrm.inverse().multiplyAffine(vecPos);
- Vector2I localPos(Math::roundToInt(vecPos.x), Math::roundToInt(vecPos.y));
- return mBounds.contains(localPos);
- }
- void GUIWidget::updateBounds() const
- {
- if(mElements.size() > 0)
- mBounds = mElements[0]->_getClippedBounds();
- for(auto& elem : mElements)
- {
- Rect2I elemBounds = elem->_getClippedBounds();
- mBounds.encapsulate(elemBounds);
- }
- }
- void GUIWidget::ownerTargetResized()
- {
- for(auto& area : mAreas)
- {
- area->updateSizeBasedOnParent(getTarget()->getWidth(), getTarget()->getHeight());
- }
- }
- void GUIWidget::ownerWindowFocusChanged()
- {
- }
- }
|