Browse Source

Dynamic Inspector Frame, ensure mouse is in 3D view

Josh Engebretson 10 years ago
parent
commit
d2e0b628d8

+ 1 - 1
Data/AtomicEditor/Resources/EditorData/AtomicEditor/editor/ui/mainframe.tb.txt

@@ -56,7 +56,7 @@ TBLayout: distribution: gravity, axis: y
 					TBContainer: skin: AEContainer, gravity: left right bottom, id: consolecontainer
 					TBContainer: skin: AEContainer, gravity: left right bottom, id: consolecontainer
 						TBEditField: multiline: 1, styling: 1, gravity: left right, id: consoletext
 						TBEditField: multiline: 1, styling: 1, gravity: left right, id: consoletext
 							text: "Hello World!"
 							text: "Hello World!"
-				TBLayout: distribution: gravity, axis: y, position: left, gravity: top bottom
+				TBLayout: distribution: gravity, axis: y, position: left, gravity: top bottom, id: inspectorlayout
 					TBEditField: text: "<color #AAAAAA>Inspector</color>", styling: 1, readonly: 1, adapt-to-content: 1, skin: 0
 					TBEditField: text: "<color #AAAAAA>Inspector</color>", styling: 1, readonly: 1, adapt-to-content: 1, skin: 0
 						font: size: 11
 						font: size: 11
 					TBLayout: distribution: gravity, id: inspectorcontainer
 					TBLayout: distribution: gravity, id: inspectorcontainer

+ 7 - 0
Source/AtomicEditor/Source/AEEvents.h

@@ -52,6 +52,13 @@ EVENT(E_EDITORPLAYSTOP, EditorPlayStop)
 
 
 }
 }
 
 
+// stop play mode
+EVENT(E_EDITORRESOURCEEDITORCHANGED, EditorResourceEditorChanged)
+{
+    PARAM(P_RESOURCEEDITOR, ResourceEditor); // ResourceEditor*
+}
+
+
 // emitted once play has started
 // emitted once play has started
 EVENT(E_EDITORPLAYSTARTED, EditorPlayStarted)
 EVENT(E_EDITORPLAYSTARTED, EditorPlayStarted)
 {
 {

+ 1 - 1
Source/AtomicEditor/Source/Editors/JSResourceEditor.cpp

@@ -49,7 +49,7 @@ JSResourceEditor ::JSResourceEditor(Context* context, const String &fullpath, TB
     currentFindPos_(-1)
     currentFindPos_(-1)
 {
 {
 
 
-    TBLayout* layout = new TBLayout();
+    TBLayout* layout = rootContentLayout_ = new TBLayout();
     layout->SetLayoutDistribution(LAYOUT_DISTRIBUTION_GRAVITY);
     layout->SetLayoutDistribution(LAYOUT_DISTRIBUTION_GRAVITY);
     layout->SetSize(container_->GetRect().w, container_->GetRect().h);
     layout->SetSize(container_->GetRect().w, container_->GetRect().h);
     layout->SetGravity(WIDGET_GRAVITY_ALL);
     layout->SetGravity(WIDGET_GRAVITY_ALL);

+ 11 - 11
Source/AtomicEditor/Source/Editors/ResourceEditor.cpp

@@ -52,33 +52,33 @@ public:
 
 
 ResourceEditor::ResourceEditor(Context* context, const String& fullpath, TBTabContainer* container):
 ResourceEditor::ResourceEditor(Context* context, const String& fullpath, TBTabContainer* container):
     Object(context), fullpath_(fullpath), container_(container),
     Object(context), fullpath_(fullpath), container_(container),
-    layout_(0), button_(0)
+    editorTabLayout_(0), rootContentLayout_(0), button_(0)
 {
 {
 
 
     String filename = GetFileNameAndExtension(fullpath_);
     String filename = GetFileNameAndExtension(fullpath_);
 
 
-    layout_ = new EditorTabLayout();
-    layout_->SetID(TBIDC("tab"));
+    editorTabLayout_ = new EditorTabLayout();
+    editorTabLayout_->SetID(TBIDC("tab"));
 
 
     button_ = new TBButton();
     button_ = new TBButton();
     button_->SetText(filename.CString());
     button_->SetText(filename.CString());
     button_->SetSqueezable(true);
     button_->SetSqueezable(true);
     button_->SetSkinBg(TBIDC("TBButton.flat"));
     button_->SetSkinBg(TBIDC("TBButton.flat"));
     button_->SetValue(1);
     button_->SetValue(1);
-    layout_->AddChild(button_);
+    editorTabLayout_->AddChild(button_);
 
 
     TBButton* closebutton = new TBButton();
     TBButton* closebutton = new TBButton();
-    layout_->AddChild(closebutton);
+    editorTabLayout_->AddChild(closebutton);
     closebutton->SetSkinBg(TBIDC("TBWindow.close"));
     closebutton->SetSkinBg(TBIDC("TBWindow.close"));
     closebutton->SetIsFocusable(false);
     closebutton->SetIsFocusable(false);
     closebutton->SetID(TBIDC("tabclose"));
     closebutton->SetID(TBIDC("tabclose"));
 
 
-    layout_->editor_ = this;
-    layout_->button_ = button_;
-    layout_->close_ = closebutton;
-    layout_->container_ = container;
+    editorTabLayout_->editor_ = this;
+    editorTabLayout_->button_ = button_;
+    editorTabLayout_->close_ = closebutton;
+    editorTabLayout_->container_ = container;
 
 
-    container_->GetTabLayout()->AddChild(layout_);
+    container_->GetTabLayout()->AddChild(editorTabLayout_);
 
 
     SubscribeToEvent(E_FILECHANGED, HANDLER(ResourceEditor, HandleFileChanged));
     SubscribeToEvent(E_FILECHANGED, HANDLER(ResourceEditor, HandleFileChanged));
 }
 }
@@ -107,7 +107,7 @@ void ResourceEditor::Close(bool navigateToAvailabeResource)
     // keep us alive through the close
     // keep us alive through the close
     SharedPtr<ResourceEditor> keepalive(this);
     SharedPtr<ResourceEditor> keepalive(this);
 
 
-    container_->GetTabLayout()->RemoveChild(layout_);
+    container_->GetTabLayout()->RemoveChild(editorTabLayout_);
 
 
     MainFrame* frame = GetSubsystem<MainFrame>();
     MainFrame* frame = GetSubsystem<MainFrame>();
     ResourceFrame* rframe = frame->GetResourceFrame();
     ResourceFrame* rframe = frame->GetResourceFrame();

+ 6 - 1
Source/AtomicEditor/Source/Editors/ResourceEditor.h

@@ -37,13 +37,18 @@ public:
     virtual bool FindText(const String& text, unsigned flags) { return false; }
     virtual bool FindText(const String& text, unsigned flags) { return false; }
     virtual void FindTextClose() { }
     virtual void FindTextClose() { }
 
 
+    virtual bool RequiresInspector() { return false; }
+
     const String& GetFullPath() { return fullpath_; }
     const String& GetFullPath() { return fullpath_; }
 
 
+    TBLayout* GetRootContentLayout() { return rootContentLayout_; }
+
 protected:
 protected:
 
 
     String fullpath_;
     String fullpath_;
     TBTabContainer* container_;
     TBTabContainer* container_;
-    EditorTabLayout* layout_;
+    EditorTabLayout* editorTabLayout_;
+    TBLayout* rootContentLayout_;
     TBButton* button_;
     TBButton* button_;
 
 
 private:
 private:

+ 1 - 1
Source/AtomicEditor/Source/Editors/SceneEditor3D/SceneEditor3D.cpp

@@ -37,7 +37,7 @@ SceneEditor3D ::SceneEditor3D(Context* context, const String &fullpath, TBTabCon
     layout_(0),
     layout_(0),
     view3DContainer_(0)
     view3DContainer_(0)
 {
 {
-    layout_ = new TBLayout();
+    layout_ = rootContentLayout_ = new TBLayout();
     layout_->SetLayoutDistribution(LAYOUT_DISTRIBUTION_GRAVITY);
     layout_->SetLayoutDistribution(LAYOUT_DISTRIBUTION_GRAVITY);
     layout_->SetSize(container_->GetRect().w, container_->GetRect().h);
     layout_->SetSize(container_->GetRect().w, container_->GetRect().h);
 
 

+ 2 - 0
Source/AtomicEditor/Source/Editors/SceneEditor3D/SceneEditor3D.h

@@ -44,6 +44,8 @@ public:
     Scene* GetScene() { return scene_; }
     Scene* GetScene() { return scene_; }
     Gizmo3D* GetGizmo() { return gizmo3D_; }
     Gizmo3D* GetGizmo() { return gizmo3D_; }
 
 
+    virtual bool RequiresInspector() { return true; }
+
 
 
 private:
 private:
 
 

+ 21 - 2
Source/AtomicEditor/Source/Editors/SceneEditor3D/SceneView3D.cpp

@@ -102,10 +102,13 @@ void SceneView3D::MoveCamera(float timeStep)
     Input* input = GetSubsystem<Input>();
     Input* input = GetSubsystem<Input>();
 
 
     // Movement speed as world units per second
     // Movement speed as world units per second
-    const float MOVE_SPEED = 20.0f;
+    float MOVE_SPEED = 20.0f;
     // Mouse sensitivity as degrees per pixel
     // Mouse sensitivity as degrees per pixel
     const float MOUSE_SENSITIVITY = 0.2f;
     const float MOUSE_SENSITIVITY = 0.2f;
 
 
+    if (input->GetKeyDown(KEY_LSHIFT) || input->GetKeyDown(KEY_RSHIFT))
+        MOVE_SPEED *= 3.0f;
+
     // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
     // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
     if (input->GetMouseButtonDown(MOUSEB_RIGHT))
     if (input->GetMouseButtonDown(MOUSEB_RIGHT))
     {
     {
@@ -170,6 +173,18 @@ void SceneView3D::DrawNodeDebug(Node* node, DebugRenderer* debug, bool drawNode)
     }
     }
 }
 }
 
 
+bool SceneView3D::MouseInView()
+{
+    UI* ui = GetSubsystem<UI>();
+    IntVector2 pos = ui->GetCursorPosition();
+
+    TBRect rect = GetWidgetDelegate()->GetRect();
+    GetWidgetDelegate()->ConvertToRoot(rect.x, rect.y);
+
+    return rect.Contains(TBPoint(pos.x_, pos.y_));
+
+}
+
 
 
 void SceneView3D::HandlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
 void SceneView3D::HandlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
 {
 {
@@ -181,6 +196,9 @@ void SceneView3D::HandlePostRenderUpdate(StringHash eventType, VariantMap& event
 
 
     }
     }
 
 
+    if (!MouseInView())
+        return;
+
     Input* input = GetSubsystem<Input>();
     Input* input = GetSubsystem<Input>();
 
 
     mouseLeftDown_ = false;
     mouseLeftDown_ = false;
@@ -276,7 +294,8 @@ void SceneView3D::HandleUpdate(StringHash eventType, VariantMap& eventData)
     // Timestep parameter is same no matter what event is being listened to
     // Timestep parameter is same no matter what event is being listened to
     float timeStep = eventData[Update::P_TIMESTEP].GetFloat();
     float timeStep = eventData[Update::P_TIMESTEP].GetFloat();
 
 
-    MoveCamera(timeStep);
+    if (MouseInView())
+        MoveCamera(timeStep);
 
 
     QueueUpdate();
     QueueUpdate();
 }
 }

+ 2 - 0
Source/AtomicEditor/Source/Editors/SceneEditor3D/SceneView3D.h

@@ -42,6 +42,8 @@ public:
 
 
 private:
 private:
 
 
+    bool MouseInView();
+
     void HandleUpdate(StringHash eventType, VariantMap& eventData);
     void HandleUpdate(StringHash eventType, VariantMap& eventData);
     void HandlePostRenderUpdate(StringHash eventType, VariantMap& eventData);
     void HandlePostRenderUpdate(StringHash eventType, VariantMap& eventData);
     void HandleEditorActiveNodeChange(StringHash eventType, VariantMap& eventData);
     void HandleEditorActiveNodeChange(StringHash eventType, VariantMap& eventData);

+ 1 - 1
Source/AtomicEditor/Source/Editors/TextResourceEditor.cpp

@@ -34,7 +34,7 @@ TextResourceEditor ::TextResourceEditor(Context* context, const String &fullpath
     currentFindPos_(-1)
     currentFindPos_(-1)
 {
 {
 
 
-    TBLayout* layout = new TBLayout();
+    TBLayout* layout = rootContentLayout_ = new TBLayout();
     layout->SetLayoutDistribution(LAYOUT_DISTRIBUTION_GRAVITY);
     layout->SetLayoutDistribution(LAYOUT_DISTRIBUTION_GRAVITY);
     layout->SetSize(container_->GetRect().w, container_->GetRect().h);
     layout->SetSize(container_->GetRect().w, container_->GetRect().h);
     layout->SetGravity(WIDGET_GRAVITY_ALL);
     layout->SetGravity(WIDGET_GRAVITY_ALL);

+ 38 - 0
Source/AtomicEditor/Source/UI/UIMainFrame.cpp

@@ -40,6 +40,8 @@
 #include "Project/AEProject.h"
 #include "Project/AEProject.h"
 #include "Project/ProjectUtils.h"
 #include "Project/ProjectUtils.h"
 
 
+#include "Editors/ResourceEditor.h"
+
 #include "Tools/External/AEExternalTooling.h"
 #include "Tools/External/AEExternalTooling.h"
 
 
 using namespace tb;
 using namespace tb;
@@ -94,6 +96,9 @@ MainFrame::MainFrame(Context* context) :
     wd->SetSize(rect.w, rect.h);
     wd->SetSize(rect.w, rect.h);
     hierarchycontainer->AddChild(wd);
     hierarchycontainer->AddChild(wd);
 
 
+    inspectorlayout_ = delegate_->GetWidgetByIDAndType<TBLayout>(TBIDC("inspectorlayout"));
+    assert(inspectorlayout_);
+
     inspectorframe_ = new InspectorFrame(context_);
     inspectorframe_ = new InspectorFrame(context_);
     TBLayout* inspectorcontainer = delegate_->GetWidgetByIDAndType<TBLayout>(TBIDC("inspectorcontainer"));
     TBLayout* inspectorcontainer = delegate_->GetWidgetByIDAndType<TBLayout>(TBIDC("inspectorcontainer"));
     assert(inspectorcontainer);
     assert(inspectorcontainer);
@@ -143,10 +148,13 @@ MainFrame::MainFrame(Context* context) :
     SubscribeToEvent(E_JAVASCRIPTSAVED, HANDLER(MainFrame, HandleJavascriptSaved));
     SubscribeToEvent(E_JAVASCRIPTSAVED, HANDLER(MainFrame, HandleJavascriptSaved));
     SubscribeToEvent(E_PLATFORMCHANGE, HANDLER(MainFrame, HandlePlatformChange));
     SubscribeToEvent(E_PLATFORMCHANGE, HANDLER(MainFrame, HandlePlatformChange));
     SubscribeToEvent(E_EDITORSHUTDOWN, HANDLER(MainFrame, HandleEditorShutdown));
     SubscribeToEvent(E_EDITORSHUTDOWN, HANDLER(MainFrame, HandleEditorShutdown));
+    SubscribeToEvent(E_EDITORRESOURCEEDITORCHANGED, HANDLER(MainFrame, HandleResourceEditorChanged));
 
 
     messageModal_ = new MessageModal(context_);
     messageModal_ = new MessageModal(context_);
     uiModalOps_ = new UIModalOps(context_);
     uiModalOps_ = new UIModalOps(context_);
 
 
+    ShowInspectorFrame(false);
+
     // show welcome frame to start
     // show welcome frame to start
     ShowWelcomeFrame();
     ShowWelcomeFrame();
 
 
@@ -243,6 +251,24 @@ UIModalOps* MainFrame::GetUIModalOps()
     return uiModalOps_;
     return uiModalOps_;
 }
 }
 
 
+InspectorFrame* MainFrame::GetInspectorFrame()
+{
+    return inspectorframe_;
+}
+
+void MainFrame::ShowInspectorFrame(bool show)
+{
+    if (!show)
+        inspectorlayout_->SetVisibilility(WIDGET_VISIBILITY_GONE);
+    else
+        inspectorlayout_->SetVisibilility(WIDGET_VISIBILITY_VISIBLE);
+}
+
+bool MainFrame::InspectorFrameVisible()
+{
+    return inspectorlayout_->GetVisibility() == WIDGET_VISIBILITY_VISIBLE;
+}
+
 void MainFrame::HandleJavascriptSaved(StringHash eventType, VariantMap& eventData)
 void MainFrame::HandleJavascriptSaved(StringHash eventType, VariantMap& eventData)
 {
 {
     UpdateJavascriptErrors();
     UpdateJavascriptErrors();
@@ -356,6 +382,7 @@ void MainFrame::ShowWelcomeFrame(bool show)
 
 
     if (show)
     if (show)
     {
     {
+        ShowInspectorFrame(false);
         welcomeframe_->UpdateRecentProjects();
         welcomeframe_->UpdateRecentProjects();
         if (!child)
         if (!child)
         {
         {
@@ -728,6 +755,17 @@ void MainFrame::RevealInFinder()
 
 
 }
 }
 
 
+void MainFrame::HandleResourceEditorChanged(StringHash eventType, VariantMap& eventData)
+{
+    ResourceEditor* editor = static_cast<ResourceEditor*>(eventData[EditorResourceEditorChanged::P_RESOURCEEDITOR].GetPtr());
+
+    if (!editor || !editor->RequiresInspector())
+        ShowInspectorFrame(false);
+    else
+        ShowInspectorFrame(true);
+
+}
+
 void MainFrame::HandlePlatformChange(StringHash eventType, VariantMap& eventData)
 void MainFrame::HandlePlatformChange(StringHash eventType, VariantMap& eventData)
 {
 {
     using namespace PlatformChange;
     using namespace PlatformChange;

+ 8 - 0
Source/AtomicEditor/Source/UI/UIMainFrame.h

@@ -58,6 +58,7 @@ public:
 
 
     ProjectFrame* GetProjectFrame();
     ProjectFrame* GetProjectFrame();
     HierarchyFrame* GetHierarchyFrame();
     HierarchyFrame* GetHierarchyFrame();
+    InspectorFrame* GetInspectorFrame();
     ResourceFrame* GetResourceFrame();
     ResourceFrame* GetResourceFrame();
     WelcomeFrame* GetWelcomeFrame();
     WelcomeFrame* GetWelcomeFrame();
     FindTextWidget* GetFindTextWidget();
     FindTextWidget* GetFindTextWidget();
@@ -68,8 +69,13 @@ public:
     // content views
     // content views
     void ShowResourceFrame(bool show = true);
     void ShowResourceFrame(bool show = true);
     void ShowWelcomeFrame(bool show = true);    
     void ShowWelcomeFrame(bool show = true);    
+
     bool ResourceFrameVisible();
     bool ResourceFrameVisible();
     bool WelcomeFrameVisible();
     bool WelcomeFrameVisible();
+    bool InspectorFrameVisible();
+
+
+    void ShowInspectorFrame(bool show);
 
 
     // reveals the current project folder in finder/explorer
     // reveals the current project folder in finder/explorer
     void RevealInFinder();
     void RevealInFinder();
@@ -92,9 +98,11 @@ private:
     void HandleJavascriptSaved(StringHash eventType, VariantMap& eventData);
     void HandleJavascriptSaved(StringHash eventType, VariantMap& eventData);
     void HandlePlatformChange(StringHash eventType, VariantMap& eventData);
     void HandlePlatformChange(StringHash eventType, VariantMap& eventData);
     void HandleEditorShutdown(StringHash eventType, VariantMap& eventData);
     void HandleEditorShutdown(StringHash eventType, VariantMap& eventData);
+    void HandleResourceEditorChanged(StringHash eventType, VariantMap& eventData);
 
 
     TBEditField* consoletext_;
     TBEditField* consoletext_;
     TBLayout* resourceviewcontainer_;
     TBLayout* resourceviewcontainer_;
+    TBLayout* inspectorlayout_;
     TBSkinImage* platformIndicator_;
     TBSkinImage* platformIndicator_;
 
 
     SharedPtr<ProjectFrame> projectframe_;
     SharedPtr<ProjectFrame> projectframe_;

+ 23 - 1
Source/AtomicEditor/Source/UI/UIResourceFrame.cpp

@@ -154,8 +154,9 @@ void ResourceFrame::EditResource(const String& fullpath)
         }
         }
 
 
         editors_[fullpath] = editor;
         editors_[fullpath] = editor;
+        editorLookup_[editor->GetRootContentLayout()] = editor;
         tabcontainer_->SetCurrentPage(tabcontainer_->GetNumPages()-1);
         tabcontainer_->SetCurrentPage(tabcontainer_->GetNumPages()-1);
-        editorLookup_[tabcontainer_->GetCurrentPageWidget()] = editor;
+
     }
     }
 
 
 }
 }
@@ -169,6 +170,27 @@ void ResourceFrame::FocusCurrentTab()
 
 
 bool ResourceFrame::OnEvent(const TBWidgetEvent &ev)
 bool ResourceFrame::OnEvent(const TBWidgetEvent &ev)
 {
 {
+    if (ev.type == EVENT_TYPE_TAB_CHANGED && ev.target == tabcontainer_)
+    {
+        TBWidget* widget = tabcontainer_->GetCurrentPageWidget();
+        if (widget)
+        {
+            if (editorLookup_.Contains(widget))
+            {
+                ResourceEditor* editor = editorLookup_[widget];
+                if (editor != currentResourceEditor_)
+                {
+                    VariantMap eventData;
+                    eventData[EditorResourceEditorChanged::P_RESOURCEEDITOR] = editor;
+                    SendEvent(E_EDITORRESOURCEEDITORCHANGED, eventData);
+                    currentResourceEditor_ = editor;
+                }
+            }
+        }
+
+        return true;
+    }
+
     if (ev.type == EVENT_TYPE_KEY_DOWN || ev.type == EVENT_TYPE_SHORTCUT
     if (ev.type == EVENT_TYPE_KEY_DOWN || ev.type == EVENT_TYPE_SHORTCUT
             || ev.type == EVENT_TYPE_CLICK || ev.type == EVENT_TYPE_RIGHT_POINTER_UP)
             || ev.type == EVENT_TYPE_CLICK || ev.type == EVENT_TYPE_RIGHT_POINTER_UP)
     {
     {

+ 2 - 0
Source/AtomicEditor/Source/UI/UIResourceFrame.h

@@ -67,6 +67,8 @@ private:
     HashMap<String, SharedPtr<ResourceEditor> > editors_;
     HashMap<String, SharedPtr<ResourceEditor> > editors_;
     HashMap<TBWidget*, SharedPtr<ResourceEditor> > editorLookup_;
     HashMap<TBWidget*, SharedPtr<ResourceEditor> > editorLookup_;
 
 
+    WeakPtr<ResourceEditor> currentResourceEditor_;
+
     SharedPtr<IssuesWidget> issueswidget_;
     SharedPtr<IssuesWidget> issueswidget_;
     SharedPtr<ErrorsWidget> errorswidget_;
     SharedPtr<ErrorsWidget> errorswidget_;
     SharedPtr<ConsoleWidget> consolewidget_;    
     SharedPtr<ConsoleWidget> consolewidget_;    

+ 13 - 2
Source/ThirdParty/TurboBadger/tb_tab_container.cpp

@@ -37,7 +37,7 @@ PreferredSize TBTabLayout::OnCalculatePreferredContentSize(const SizeConstraints
 
 
 TBTabContainer::TBTabContainer()
 TBTabContainer::TBTabContainer()
 	: m_need_page_update(true)
 	: m_need_page_update(true)
-	, m_current_page(0)
+    , m_current_page(-1)
 	, m_align(TB_ALIGN_TOP)
 	, m_align(TB_ALIGN_TOP)
 {
 {
 	AddChild(&m_root_layout);
 	AddChild(&m_root_layout);
@@ -75,8 +75,9 @@ void TBTabContainer::SetAxis(AXIS axis)
 
 
 void TBTabContainer::SetValue(int index)
 void TBTabContainer::SetValue(int index)
 {
 {
-	if (index == m_current_page)
+    if (index == m_current_page || !GetNumPages())
 		return;
 		return;
+
 	m_current_page = index;
 	m_current_page = index;
 
 
 	// Update the pages visibility and tabs pressed value.
 	// Update the pages visibility and tabs pressed value.
@@ -89,6 +90,9 @@ void TBTabContainer::SetValue(int index)
 		page->SetVisibilility(active ? WIDGET_VISIBILITY_VISIBLE : WIDGET_VISIBILITY_INVISIBLE);
 		page->SetVisibilility(active ? WIDGET_VISIBILITY_VISIBLE : WIDGET_VISIBILITY_INVISIBLE);
 		tab->SetValue(active ? 1 : 0);
 		tab->SetValue(active ? 1 : 0);
 	}
 	}
+
+    TBWidgetEvent ev(EVENT_TYPE_TAB_CHANGED);
+    InvokeEvent(ev);
 }
 }
 
 
 int TBTabContainer::GetNumPages()
 int TBTabContainer::GetNumPages()
@@ -96,11 +100,18 @@ int TBTabContainer::GetNumPages()
 	int count = 0;
 	int count = 0;
 	for (TBWidget *tab = m_tab_layout.GetFirstChild(); tab; tab = tab->GetNext())
 	for (TBWidget *tab = m_tab_layout.GetFirstChild(); tab; tab = tab->GetNext())
 		count++;
 		count++;
+
+    if (!count)
+        m_current_page = -1;
+
 	return count;
 	return count;
 }
 }
 
 
 TBWidget *TBTabContainer::GetCurrentPageWidget() const
 TBWidget *TBTabContainer::GetCurrentPageWidget() const
 {
 {
+    if (m_current_page == -1)
+        return nullptr;
+
 	return m_content_root.GetChildFromIndex(m_current_page);
 	return m_content_root.GetChildFromIndex(m_current_page);
 }
 }
 
 

+ 3 - 0
Source/ThirdParty/TurboBadger/tb_widgets.h

@@ -82,6 +82,9 @@ enum EVENT_TYPE {
 		the widget. The event is guaranteed to be a TBWidgetEventFileDrop. */
 		the widget. The event is guaranteed to be a TBWidgetEventFileDrop. */
 	EVENT_TYPE_FILE_DROP,
 	EVENT_TYPE_FILE_DROP,
 
 
+    /** Invoked by the platform when a tab container's tab changed */
+    EVENT_TYPE_TAB_CHANGED,
+
 	/** Custom event. Not used internally. ref_id may be used for additional type info. */
 	/** Custom event. Not used internally. ref_id may be used for additional type info. */
 	EVENT_TYPE_CUSTOM
 	EVENT_TYPE_CUSTOM
 };
 };