Browse Source

Allow to disable rendering of the whole UI (except for the cursor and modal elements) by setting the UI root to not visible. Added new function UIElement::IsVisibleEffective() which checks for propagated visibility. Make sure to clear focus also if a child element (that has focus) becomes effectively invisible. Closes #811.

Lasse Öörni 10 years ago
parent
commit
fba5948ab0

+ 2 - 0
Source/Urho3D/LuaScript/pkgs/UI/UIElement.pkg

@@ -181,6 +181,7 @@ class UIElement : public Animatable
     bool IsEditable() const;
     bool IsEditable() const;
     bool IsSelected() const;
     bool IsSelected() const;
     bool IsVisible() const;
     bool IsVisible() const;
+    bool IsVisibleEffective() const;
     bool IsHovering() const;
     bool IsHovering() const;
     bool IsInternal() const;
     bool IsInternal() const;
     bool HasColorGradient() const;
     bool HasColorGradient() const;
@@ -255,6 +256,7 @@ class UIElement : public Animatable
     tolua_property__is_set bool editable;
     tolua_property__is_set bool editable;
     tolua_property__is_set bool selected;
     tolua_property__is_set bool selected;
     tolua_property__is_set bool visible;
     tolua_property__is_set bool visible;
+    tolua_readonly tolua_property__is_set bool visibleEffective;
     tolua_property__is_set bool hovering;
     tolua_property__is_set bool hovering;
     tolua_property__is_set bool internal;
     tolua_property__is_set bool internal;
     tolua_readonly tolua_property__has_set bool colorGradient;
     tolua_readonly tolua_property__has_set bool colorGradient;

+ 1 - 0
Source/Urho3D/Script/APITemplates.h

@@ -1112,6 +1112,7 @@ template <class T> void RegisterUIElement(asIScriptEngine* engine, const char* c
     }
     }
     engine->RegisterObjectMethod(className, "void set_visible(bool)", asMETHOD(T, SetVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void set_visible(bool)", asMETHOD(T, SetVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool get_visible() const", asMETHOD(T, IsVisible), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool get_visible() const", asMETHOD(T, IsVisible), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "bool get_visibleEffective() const", asMETHOD(T, IsVisibleEffective), asCALL_THISCALL);
     if (!isSprite)
     if (!isSprite)
     {
     {
         engine->RegisterObjectMethod(className, "bool get_hovering() const", asMETHOD(T, IsHovering), asCALL_THISCALL);
         engine->RegisterObjectMethod(className, "bool get_hovering() const", asMETHOD(T, IsHovering), asCALL_THISCALL);

+ 2 - 1
Source/Urho3D/UI/UI.cpp

@@ -405,7 +405,8 @@ void UI::RenderUpdate()
     vertexData_.Clear();
     vertexData_.Clear();
     const IntVector2& rootSize = rootElement_->GetSize();
     const IntVector2& rootSize = rootElement_->GetSize();
     IntRect currentScissor = IntRect(0, 0, rootSize.x_, rootSize.y_);
     IntRect currentScissor = IntRect(0, 0, rootSize.x_, rootSize.y_);
-    GetBatches(rootElement_, currentScissor);
+    if (rootElement_->IsVisible())
+        GetBatches(rootElement_, currentScissor);
 
 
     // Save the batch size of the non-modal batches for later use
     // Save the batch size of the non-modal batches for later use
     nonModalBatchSize_ = batches_.Size();
     nonModalBatchSize_ = batches_.Size();

+ 23 - 5
Source/Urho3D/UI/UIElement.cpp

@@ -883,8 +883,7 @@ void UIElement::SetFocusMode(FocusMode mode)
 void UIElement::SetFocus(bool enable)
 void UIElement::SetFocus(bool enable)
 {
 {
     // Invisible elements should not receive focus
     // Invisible elements should not receive focus
-    // \todo Needs rework when/if visibility starts propagating down the UI hierarchy
-    if (focusMode_ < FM_FOCUSABLE || !visible_)
+    if (focusMode_ < FM_FOCUSABLE || !IsVisibleEffective())
         enable = false;
         enable = false;
 
 
     UI* ui = GetSubsystem<UI>();
     UI* ui = GetSubsystem<UI>();
@@ -922,9 +921,13 @@ void UIElement::SetVisible(bool enable)
         eventData[P_VISIBLE] = visible_;
         eventData[P_VISIBLE] = visible_;
         SendEvent(E_VISIBLECHANGED, eventData);
         SendEvent(E_VISIBLECHANGED, eventData);
 
 
-        // Lose focus when hidden
-        if (!visible_ && HasFocus())
-            SetFocus(false);
+        // If the focus element becomes effectively hidden, clear focus
+        if (!enable)
+        {
+            UIElement* focusElement = GetSubsystem<UI>()->GetFocusElement();
+            if (focusElement && !focusElement->IsVisibleEffective())
+                focusElement->SetFocus(false);
+        }
     }
     }
 }
 }
 
 
@@ -1423,6 +1426,21 @@ bool UIElement::HasFocus() const
     return GetSubsystem<UI>()->GetFocusElement() == this;
     return GetSubsystem<UI>()->GetFocusElement() == this;
 }
 }
 
 
+bool UIElement::IsVisibleEffective() const
+{
+    bool visible = visible_;
+    const UIElement* element = parent_;
+    
+    // Traverse the parent chain
+    while (visible && element)
+    {
+        visible &= element->visible_;
+        element = element->parent_;
+    }
+    
+    return visible;
+}
+
 const String& UIElement::GetAppliedStyle() const
 const String& UIElement::GetAppliedStyle() const
 {
 {
     return appliedStyle_ == GetTypeName() ? String::EMPTY : appliedStyle_;
     return appliedStyle_ == GetTypeName() ? String::EMPTY : appliedStyle_;

+ 5 - 2
Source/Urho3D/UI/UIElement.h

@@ -276,7 +276,7 @@ public:
     void SetFocus(bool enable);
     void SetFocus(bool enable);
     /// Set selected mode. Actual meaning is element dependent, for example constant hover or pressed effect.
     /// Set selected mode. Actual meaning is element dependent, for example constant hover or pressed effect.
     void SetSelected(bool enable);
     void SetSelected(bool enable);
-    /// Set whether is visible.
+    /// Set whether is visible. Visibility propagates to child elements.
     void SetVisible(bool enable);
     void SetVisible(bool enable);
     /// Set focus mode.
     /// Set focus mode.
     void SetFocusMode(FocusMode mode);
     void SetFocusMode(FocusMode mode);
@@ -438,8 +438,11 @@ public:
     /// Return whether is selected. Actual meaning is element dependent.
     /// Return whether is selected. Actual meaning is element dependent.
     bool IsSelected() const { return selected_; }
     bool IsSelected() const { return selected_; }
 
 
-    /// Return whether is visible.
+    /// Return whether element itself should be visible. Elements can be also hidden due to the parent being not visible, use IsVisibleEffective() to check.
     bool IsVisible() const { return visible_; }
     bool IsVisible() const { return visible_; }
+    
+    /// Return whether element is effectively visible (parent element chain is visible.)
+    bool IsVisibleEffective() const;
 
 
     /// Return whether the cursor is hovering on this element.
     /// Return whether the cursor is hovering on this element.
     bool IsHovering() const { return hovering_; }
     bool IsHovering() const { return hovering_; }

+ 2 - 0
bin/Data/Scripts/Editor/EditorUI.as

@@ -1553,6 +1553,8 @@ void HideUI(bool hide = true)
     if (uiHidden == hide)
     if (uiHidden == hide)
         return;
         return;
 
 
+    // Note: we could set ui.root.visible = false and it would hide the whole hierarchy.
+    // However in this case we need the editorUIElement to stay visible
     bool visible = !(uiHidden = hide);
     bool visible = !(uiHidden = hide);
     Array<UIElement@> children = ui.root.GetChildren();
     Array<UIElement@> children = ui.root.GetChildren();
     for (uint i = 0; i < children.length; ++i)
     for (uint i = 0; i < children.length; ++i)