|
|
@ -9,9 +9,8 @@
|
|
|
|
#include <framework/graphics/graphics.h>
|
|
|
|
#include <framework/graphics/graphics.h>
|
|
|
|
#include "uianchor.h"
|
|
|
|
#include "uianchor.h"
|
|
|
|
|
|
|
|
|
|
|
|
UIWidget::UIWidget(UIWidgetType type)
|
|
|
|
UIWidget::UIWidget()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
m_type = type;
|
|
|
|
|
|
|
|
m_visible = true;
|
|
|
|
m_visible = true;
|
|
|
|
m_enabled = true;
|
|
|
|
m_enabled = true;
|
|
|
|
m_hovered = false;
|
|
|
|
m_hovered = false;
|
|
|
@ -37,12 +36,6 @@ UIWidget::~UIWidget()
|
|
|
|
logWarning("widget '", m_id, "' was destructed without being explicit destroyed");
|
|
|
|
logWarning("widget '", m_id, "' was destructed without being explicit destroyed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
UIWidgetPtr UIWidget::create()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
UIWidgetPtr widget(new UIWidget);
|
|
|
|
|
|
|
|
return widget;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::destroy()
|
|
|
|
void UIWidget::destroy()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
//TODO: onDestroy event
|
|
|
|
//TODO: onDestroy event
|
|
|
@ -86,7 +79,7 @@ void UIWidget::destroyCheck()
|
|
|
|
logWarning("destroyed widget with id '",m_id,"', but it still have ",realUseCount," references left");
|
|
|
|
logWarning("destroyed widget with id '",m_id,"', but it still have ",realUseCount," references left");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::loadStyleFromOTML(const OTMLNodePtr& styleNode)
|
|
|
|
void UIWidget::onStyleApply(const OTMLNodePtr& styleNode)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
@ -236,7 +229,7 @@ void UIWidget::setStyle(const std::string& styleName)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
OTMLNodePtr styleNode = g_ui.getStyle(styleName);
|
|
|
|
OTMLNodePtr styleNode = g_ui.getStyle(styleName);
|
|
|
|
loadStyleFromOTML(styleNode);
|
|
|
|
onStyleApply(styleNode);
|
|
|
|
|
|
|
|
|
|
|
|
// forces layout recalculation
|
|
|
|
// forces layout recalculation
|
|
|
|
updateLayout();
|
|
|
|
updateLayout();
|
|
|
@ -260,10 +253,9 @@ void UIWidget::setRect(const Rect& rect)
|
|
|
|
UIWidgetPtr self = asUIWidget();
|
|
|
|
UIWidgetPtr self = asUIWidget();
|
|
|
|
g_dispatcher.addEvent([self, oldRect]() {
|
|
|
|
g_dispatcher.addEvent([self, oldRect]() {
|
|
|
|
self->m_updateEventScheduled = false;
|
|
|
|
self->m_updateEventScheduled = false;
|
|
|
|
UIRectUpdateEvent e(oldRect, self->getRect());
|
|
|
|
|
|
|
|
// this widget could be destroyed before the event happens
|
|
|
|
// this widget could be destroyed before the event happens
|
|
|
|
if(!self->isDestroyed())
|
|
|
|
if(!self->isDestroyed())
|
|
|
|
self->onRectUpdate(e);
|
|
|
|
self->onGeometryUpdate(oldRect, self->getRect());
|
|
|
|
});
|
|
|
|
});
|
|
|
|
m_updateEventScheduled = true;
|
|
|
|
m_updateEventScheduled = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -431,7 +423,7 @@ UIWidgetPtr UIWidget::backwardsGetWidgetById(const std::string& id)
|
|
|
|
return widget;
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::focusChild(const UIWidgetPtr& focusedChild, FocusReason reason)
|
|
|
|
void UIWidget::focusChild(const UIWidgetPtr& focusedChild, UI::FocusReason reason)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
@ -439,14 +431,10 @@ void UIWidget::focusChild(const UIWidgetPtr& focusedChild, FocusReason reason)
|
|
|
|
UIWidgetPtr oldFocused = m_focusedChild;
|
|
|
|
UIWidgetPtr oldFocused = m_focusedChild;
|
|
|
|
m_focusedChild = focusedChild;
|
|
|
|
m_focusedChild = focusedChild;
|
|
|
|
|
|
|
|
|
|
|
|
if(oldFocused) {
|
|
|
|
if(oldFocused)
|
|
|
|
UIFocusEvent e(reason, false);
|
|
|
|
oldFocused->onFocusChange(false, reason);
|
|
|
|
oldFocused->onFocusChange(e);
|
|
|
|
if(focusedChild)
|
|
|
|
}
|
|
|
|
focusedChild->onFocusChange(focusedChild->hasFocus(), reason);
|
|
|
|
if(focusedChild) {
|
|
|
|
|
|
|
|
UIFocusEvent e(reason, focusedChild->hasFocus());
|
|
|
|
|
|
|
|
focusedChild->onFocusChange(e);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -469,7 +457,7 @@ void UIWidget::addChild(const UIWidgetPtr& childToAdd)
|
|
|
|
|
|
|
|
|
|
|
|
// always focus new children
|
|
|
|
// always focus new children
|
|
|
|
if(childToAdd->isFocusable() && childToAdd->isExplicitlyVisible() && childToAdd->isExplicitlyEnabled())
|
|
|
|
if(childToAdd->isFocusable() && childToAdd->isExplicitlyVisible() && childToAdd->isExplicitlyEnabled())
|
|
|
|
focusChild(childToAdd, ActiveFocusReason);
|
|
|
|
focusChild(childToAdd, UI::ActiveFocusReason);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::insertChild(const UIWidgetPtr& childToInsert, int index)
|
|
|
|
void UIWidget::insertChild(const UIWidgetPtr& childToInsert, int index)
|
|
|
@ -506,7 +494,7 @@ void UIWidget::removeChild(const UIWidgetPtr& childToRemove)
|
|
|
|
|
|
|
|
|
|
|
|
// defocus if needed
|
|
|
|
// defocus if needed
|
|
|
|
if(m_focusedChild == childToRemove)
|
|
|
|
if(m_focusedChild == childToRemove)
|
|
|
|
focusChild(nullptr, ActiveFocusReason);
|
|
|
|
focusChild(nullptr, UI::ActiveFocusReason);
|
|
|
|
|
|
|
|
|
|
|
|
// try to unlock
|
|
|
|
// try to unlock
|
|
|
|
unlockChild(childToRemove);
|
|
|
|
unlockChild(childToRemove);
|
|
|
@ -521,14 +509,13 @@ void UIWidget::removeChild(const UIWidgetPtr& childToRemove)
|
|
|
|
childToRemove->setParent(nullptr);
|
|
|
|
childToRemove->setParent(nullptr);
|
|
|
|
|
|
|
|
|
|
|
|
// recalculate anchors
|
|
|
|
// recalculate anchors
|
|
|
|
UIWidgetPtr parent = getRootParent();
|
|
|
|
getRootParent()->recalculateAnchoredWidgets();
|
|
|
|
parent->recalculateAnchoredWidgets();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// may need to update children layout
|
|
|
|
// may need to update children layout
|
|
|
|
updateChildrenLayout();
|
|
|
|
updateChildrenLayout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::focusNextChild(FocusReason reason)
|
|
|
|
void UIWidget::focusNextChild(UI::FocusReason reason)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
@ -578,7 +565,7 @@ void UIWidget::lockChild(const UIWidgetPtr& childToLock)
|
|
|
|
|
|
|
|
|
|
|
|
// lock child focus
|
|
|
|
// lock child focus
|
|
|
|
if(childToLock->isFocusable())
|
|
|
|
if(childToLock->isFocusable())
|
|
|
|
focusChild(childToLock, ActiveFocusReason);
|
|
|
|
focusChild(childToLock, UI::ActiveFocusReason);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::unlockChild(const UIWidgetPtr& childToUnlock)
|
|
|
|
void UIWidget::unlockChild(const UIWidgetPtr& childToUnlock)
|
|
|
@ -827,17 +814,25 @@ void UIWidget::computeAnchoredWidgets()
|
|
|
|
child->computeAnchoredWidgets();
|
|
|
|
child->computeAnchoredWidgets();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::onFocusChange(UIFocusEvent& event)
|
|
|
|
void UIWidget::onGeometryUpdate(const Rect& oldRect, const Rect& newRect)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::onFocusChange(bool focused, UI::FocusReason reason)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(m_focusedChild)
|
|
|
|
if(m_focusedChild)
|
|
|
|
m_focusedChild->onFocusChange(event);
|
|
|
|
m_focusedChild->onFocusChange(focused, reason);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::onKeyPress(UIKeyEvent& event)
|
|
|
|
void UIWidget::onHoverChange(bool hovered)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
event.ignore();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool UIWidget::onKeyPress(uchar keyCode, char keyChar, int keyboardModifiers)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
UIWidgetList children = m_children;
|
|
|
@ -847,21 +842,18 @@ void UIWidget::onKeyPress(UIKeyEvent& event)
|
|
|
|
|
|
|
|
|
|
|
|
// key events go only to containers or focused child
|
|
|
|
// key events go only to containers or focused child
|
|
|
|
if(child->hasChildren() || (child->isFocusable() && child->hasFocus())) {
|
|
|
|
if(child->hasChildren() || (child->isFocusable() && child->hasFocus())) {
|
|
|
|
event.accept();
|
|
|
|
if(child->onKeyPress(keyCode, keyChar, keyboardModifiers))
|
|
|
|
child->onKeyPress(event);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(event.isAccepted())
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::onKeyRelease(UIKeyEvent& event)
|
|
|
|
bool UIWidget::onKeyRelease(uchar keyCode, char keyChar, int keyboardModifiers)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
|
event.ignore();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
@ -870,21 +862,18 @@ void UIWidget::onKeyRelease(UIKeyEvent& event)
|
|
|
|
|
|
|
|
|
|
|
|
// key events go only to containers or focused child
|
|
|
|
// key events go only to containers or focused child
|
|
|
|
if(child->hasChildren() || (child->isFocusable() && child->hasFocus())) {
|
|
|
|
if(child->hasChildren() || (child->isFocusable() && child->hasFocus())) {
|
|
|
|
event.accept();
|
|
|
|
if(child->onKeyRelease(keyCode, keyChar, keyboardModifiers))
|
|
|
|
child->onKeyRelease(event);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(event.isAccepted())
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::onMousePress(UIMouseEvent& event)
|
|
|
|
bool UIWidget::onMousePress(const Point& mousePos, UI::MouseButton button)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
|
event.ignore();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
@ -892,26 +881,23 @@ void UIWidget::onMousePress(UIMouseEvent& event)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
// mouse press events only go to children that contains the mouse position
|
|
|
|
// mouse press events only go to children that contains the mouse position
|
|
|
|
if(child->getRect().contains(event.pos()) && child == getChildByPos(event.pos())) {
|
|
|
|
if(child->getRect().contains(mousePos) && child == getChildByPos(mousePos)) {
|
|
|
|
// focus it
|
|
|
|
// focus it
|
|
|
|
if(child->isFocusable())
|
|
|
|
if(child->isFocusable())
|
|
|
|
focusChild(child, MouseFocusReason);
|
|
|
|
focusChild(child, UI::MouseFocusReason);
|
|
|
|
|
|
|
|
|
|
|
|
event.accept();
|
|
|
|
if(child->onMousePress(mousePos, button))
|
|
|
|
child->onMousePress(event);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(event.isAccepted())
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::onMouseRelease(UIMouseEvent& event)
|
|
|
|
bool UIWidget::onMouseRelease(const Point& mousePos, UI::MouseButton button)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
|
event.ignore();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
@ -919,52 +905,46 @@ void UIWidget::onMouseRelease(UIMouseEvent& event)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
// mouse release events go to all children
|
|
|
|
// mouse release events go to all children
|
|
|
|
event.accept();
|
|
|
|
if(child->onMouseRelease(mousePos, button))
|
|
|
|
child->onMouseRelease(event);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
if(event.isAccepted())
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::onMouseMove(UIMouseEvent& event)
|
|
|
|
bool UIWidget::onMouseMove(const Point& mousePos, const Point& mouseMoved)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
|
event.ignore();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
|
|
|
if(!child->isExplicitlyEnabled() || !child->isExplicitlyVisible())
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
// check if the mouse is relally over this child
|
|
|
|
// check if the mouse is really over this child
|
|
|
|
bool overChild = (isHovered() &&
|
|
|
|
bool overChild = (isHovered() &&
|
|
|
|
child->getRect().contains(event.pos()) &&
|
|
|
|
child->getRect().contains(mousePos) &&
|
|
|
|
child == getChildByPos(event.pos()));
|
|
|
|
child == getChildByPos(mousePos));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// trigger hover events
|
|
|
|
if(overChild != child->isHovered()) {
|
|
|
|
if(overChild != child->isHovered()) {
|
|
|
|
child->setHovered(overChild);
|
|
|
|
child->setHovered(overChild);
|
|
|
|
|
|
|
|
child->onHoverChange(overChild);
|
|
|
|
UIHoverEvent e(overChild);
|
|
|
|
|
|
|
|
child->onHoverChange(e);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// mouse move events go to all children
|
|
|
|
// mouse move events go to all children
|
|
|
|
event.accept();
|
|
|
|
if(child->onMouseMove(mousePos, mouseMoved))
|
|
|
|
child->onMouseMove(event);
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
|
|
if(event.isAccepted())
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void UIWidget::onMouseWheel(UIMouseEvent& event)
|
|
|
|
bool UIWidget::onMouseWheel(const Point& mousePos, UI::MouseWheelDirection direction)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
assert(!m_destroyed);
|
|
|
|
assert(!m_destroyed);
|
|
|
|
|
|
|
|
|
|
|
|
event.ignore();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
// do a backup of children list, because it may change while looping it
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
UIWidgetList children = m_children;
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
|
for(const UIWidgetPtr& child : children) {
|
|
|
@ -972,12 +952,11 @@ void UIWidget::onMouseWheel(UIMouseEvent& event)
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
// mouse wheel events only go to children that contains the mouse position
|
|
|
|
// mouse wheel events only go to children that contains the mouse position
|
|
|
|
if(child->getRect().contains(event.pos()) && child == getChildByPos(event.pos())) {
|
|
|
|
if(child->getRect().contains(mousePos) && child == getChildByPos(mousePos)) {
|
|
|
|
event.accept();
|
|
|
|
if(child->onMouseWheel(mousePos, direction))
|
|
|
|
child->onMouseWheel(event);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(event.isAccepted())
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|