Browse Source

New UI Work

Josh Engebretson 10 years ago
parent
commit
a25cd7a855

+ 31 - 1
Source/Atomic/UI/UI.cpp

@@ -9,6 +9,7 @@
 #include <TurboBadger/tb_widgets_reader.h>
 #include <TurboBadger/tb_widgets_reader.h>
 #include <TurboBadger/tb_window.h>
 #include <TurboBadger/tb_window.h>
 #include <TurboBadger/tb_editfield.h>
 #include <TurboBadger/tb_editfield.h>
+#include <TurboBadger/image/tb_image_widget.h>
 
 
 void register_tbbf_font_renderer();
 void register_tbbf_font_renderer();
 void register_stb_font_renderer();
 void register_stb_font_renderer();
@@ -30,6 +31,8 @@ using namespace tb;
 #include "UIButton.h"
 #include "UIButton.h"
 #include "UITextField.h"
 #include "UITextField.h"
 #include "UIEditField.h"
 #include "UIEditField.h"
+#include "UILayout.h"
+#include "UIImageWidget.h"
 
 
 namespace tb
 namespace tb
 {
 {
@@ -342,7 +345,14 @@ void UI::TBFileReader(const char* filename, void** data, unsigned* length)
 
 
 void UI::GetTBIDString(unsigned id, String& value)
 void UI::GetTBIDString(unsigned id, String& value)
 {
 {
-    value = tbidToString_[id];
+    if (!id)
+    {
+        value = "";
+    }
+    else
+    {
+        value = tbidToString_[id];
+    }
 }
 }
 
 
 void UI::TBIDRegisterStringCallback(unsigned id, const char* value)
 void UI::TBIDRegisterStringCallback(unsigned id, const char* value)
@@ -375,11 +385,24 @@ void UI::HandleUpdate(StringHash eventType, VariantMap& eventData)
     TBMessageHandler::ProcessMessages();
     TBMessageHandler::ProcessMessages();
 }
 }
 
 
+bool UI::IsWidgetWrapped(tb::TBWidget* widget)
+{
+    return widgetWrap_.Contains(widget);
+}
+
 UIWidget* UI::WrapWidget(tb::TBWidget* widget)
 UIWidget* UI::WrapWidget(tb::TBWidget* widget)
 {
 {
     if (widgetWrap_.Contains(widget))
     if (widgetWrap_.Contains(widget))
         return widgetWrap_[widget];
         return widgetWrap_[widget];
 
 
+    if (widget->IsOfType<TBLayout>())
+    {
+        UILayout* layout = new UILayout(context_, false);
+        layout->SetWidget(widget);
+        widgetWrap_[widget] = layout;
+        return layout;
+    }
+
     if (widget->IsOfType<TBButton>())
     if (widget->IsOfType<TBButton>())
     {
     {
         // don't wrap the close button of a TBWindow.close
         // don't wrap the close button of a TBWindow.close
@@ -408,6 +431,13 @@ UIWidget* UI::WrapWidget(tb::TBWidget* widget)
         return editfield;
         return editfield;
     }
     }
 
 
+    if (widget->IsOfType<TBImageWidget>())
+    {
+        UIImageWidget* imagewidget = new UIImageWidget(context_, false);
+        imagewidget->SetWidget(widget);
+        widgetWrap_[widget] = imagewidget;
+        return imagewidget;
+    }
 
 
     return 0;
     return 0;
 }
 }

+ 1 - 0
Source/Atomic/UI/UI.h

@@ -45,6 +45,7 @@ public:
     void AddFont(const String& fontFile, const String &name);
     void AddFont(const String& fontFile, const String &name);
     void SetDefaultFont(const String& name, int size);
     void SetDefaultFont(const String& name, int size);
 
 
+    bool IsWidgetWrapped(tb::TBWidget* widget);
     UIWidget* WrapWidget(tb::TBWidget* widget);
     UIWidget* WrapWidget(tb::TBWidget* widget);
 
 
     void GetTBIDString(unsigned id, String& value);
     void GetTBIDString(unsigned id, String& value);

+ 3 - 30
Source/Atomic/UI/UIButton.cpp

@@ -3,6 +3,7 @@
 #include <TurboBadger/tb_widgets_common.h>
 #include <TurboBadger/tb_widgets_common.h>
 
 
 #include "UIEvents.h"
 #include "UIEvents.h"
+#include "UI.h"
 #include "UIButton.h"
 #include "UIButton.h"
 
 
 using namespace tb;
 using namespace tb;
@@ -25,36 +26,8 @@ UIButton::~UIButton()
 }
 }
 
 
 bool UIButton::OnEvent(const tb::TBWidgetEvent &ev)
 bool UIButton::OnEvent(const tb::TBWidgetEvent &ev)
-{       
-    if (ev.type == EVENT_TYPE_CLICK)
-    {        
-        if (ev.target == widget_) // button clicked itself
-        {
-            VariantMap eventData;
-            ConvertEvent(this, ev, eventData);
-            SendEvent(E_WIDGETEVENT, eventData);
-
-            // this is catching the window close button
-            return true;
-        }
-
-        if (ev.target && ev.target->GetID() == TBID("__popup-menu"))
-        {
-            // popup menu
-
-            if (JSGetHeapPtr())
-            {
-                VariantMap eventData;
-                eventData[PopupMenuSelect::P_BUTTON] = this;
-                eventData[PopupMenuSelect::P_REFID] = (unsigned) ev.ref_id;
-                SendEvent(E_POPUPMENUSELECT, eventData);
-            }
-
-            return true;
-        }
-    }
-
-    return false;
+{
+    return UIWidget::OnEvent(ev);
 }
 }
 
 
 }
 }

+ 2 - 1
Source/Atomic/UI/UIEvents.h

@@ -29,6 +29,7 @@ namespace Atomic
 
 
 EVENT(E_WIDGETEVENT, WidgetEvent)
 EVENT(E_WIDGETEVENT, WidgetEvent)
 {
 {
+    PARAM(P_HANDLER, Handler);           // UIWidget pointer of widget's OnEvent we are in
     PARAM(P_TARGET, Target);             // UIWidget pointer
     PARAM(P_TARGET, Target);             // UIWidget pointer
     PARAM(P_TYPE, Type);                 // EVENT_TYPE enum
     PARAM(P_TYPE, Type);                 // EVENT_TYPE enum
     PARAM(P_X, X);                       // int
     PARAM(P_X, X);                       // int
@@ -39,7 +40,7 @@ EVENT(E_WIDGETEVENT, WidgetEvent)
     PARAM(P_KEY, Key);                   // int
     PARAM(P_KEY, Key);                   // int
     PARAM(P_SPECIALKEY, SpecialKey);     // enum SPECIAL_KEY
     PARAM(P_SPECIALKEY, SpecialKey);     // enum SPECIAL_KEY
     PARAM(P_MODIFIERKEYS, ModifierKeys); // enum MODIFIER_KEYS
     PARAM(P_MODIFIERKEYS, ModifierKeys); // enum MODIFIER_KEYS
-    PARAM(P_ID, ID);                     // unsigned (TBID)
+    PARAM(P_REFID, RefID);                     // unsigned (TBID)
     PARAM(P_TOUCH, Touch);               // bool
     PARAM(P_TOUCH, Touch);               // bool
 }
 }
 
 

+ 36 - 0
Source/Atomic/UI/UIImageWidget.cpp

@@ -0,0 +1,36 @@
+
+#include <TurboBadger/tb_widgets.h>
+#include <TurboBadger/tb_widgets_common.h>
+#include <TurboBadger/image/tb_image_widget.h>
+
+#include <Atomic/IO/Log.h>
+
+#include "UIEvents.h"
+#include "UIWidget.h"
+#include "UIImageWidget.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+UIImageWidget::UIImageWidget(Context* context, bool createWidget) : UIWidget(context, false)
+{
+    if (createWidget)
+    {
+        widget_ = new TBImageWidget();
+        widget_->SetDelegate(this);
+    }
+}
+
+UIImageWidget::~UIImageWidget()
+{
+    LOGINFOF("Hey!");
+}
+
+bool UIImageWidget::OnEvent(const tb::TBWidgetEvent &ev)
+{
+    return UIWidget::OnEvent(ev);
+}
+
+}

+ 27 - 0
Source/Atomic/UI/UIImageWidget.h

@@ -0,0 +1,27 @@
+
+#pragma once
+
+#include "UIWidget.h"
+
+namespace Atomic
+{
+
+
+class UIImageWidget : public UIWidget
+{
+    OBJECT(UIImageWidget)
+
+public:
+
+    UIImageWidget(Context* context, bool createWidget = true);
+    virtual ~UIImageWidget();
+
+protected:
+
+    virtual bool OnEvent(const tb::TBWidgetEvent &ev);
+
+private:
+
+};
+
+}

+ 33 - 0
Source/Atomic/UI/UILayout.cpp

@@ -0,0 +1,33 @@
+
+#include <TurboBadger/tb_widgets.h>
+#include <TurboBadger/tb_widgets_common.h>
+#include <TurboBadger/image/tb_image_widget.h>
+
+#include "UIEvents.h"
+#include "UIWidget.h"
+#include "UILayout.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+UILayout::UILayout(Context* context, bool createWidget) : UIWidget(context, false)
+{
+    if (createWidget)
+    {
+        widget_ = new TBLayout();
+        widget_->SetDelegate(this);
+    }
+}
+
+UILayout::~UILayout()
+{
+}
+
+bool UILayout::OnEvent(const tb::TBWidgetEvent &ev)
+{
+    return UIWidget::OnEvent(ev);
+}
+
+}

+ 27 - 0
Source/Atomic/UI/UILayout.h

@@ -0,0 +1,27 @@
+
+#pragma once
+
+#include "UIWidget.h"
+
+namespace Atomic
+{
+
+
+class UILayout : public UIWidget
+{
+    OBJECT(UILayout)
+
+public:
+
+    UILayout(Context* context, bool createWidget = true);
+    virtual ~UILayout();
+
+protected:
+
+    virtual bool OnEvent(const tb::TBWidgetEvent &ev);
+
+private:
+
+};
+
+}

+ 82 - 3
Source/Atomic/UI/UIWidget.cpp

@@ -62,9 +62,10 @@ void UIWidget::SetWidget(tb::TBWidget* widget)
     widget_->SetDelegate(this);
     widget_->SetDelegate(this);
 }
 }
 
 
-void UIWidget::ConvertEvent(UIWidget* target, const tb::TBWidgetEvent &ev, VariantMap& data)
+void UIWidget::ConvertEvent(UIWidget *handler, UIWidget* target, const tb::TBWidgetEvent &ev, VariantMap& data)
 {
 {
     using namespace WidgetEvent;
     using namespace WidgetEvent;
+    data[P_HANDLER] = handler;
     data[P_TARGET] = target;
     data[P_TARGET] = target;
     data[P_TYPE] = (unsigned) ev.type;
     data[P_TYPE] = (unsigned) ev.type;
     data[P_X] = ev.target_x;
     data[P_X] = ev.target_x;
@@ -75,7 +76,7 @@ void UIWidget::ConvertEvent(UIWidget* target, const tb::TBWidgetEvent &ev, Varia
     data[P_KEY] = ev.key;
     data[P_KEY] = ev.key;
     data[P_SPECIALKEY] = (unsigned) ev.special_key;
     data[P_SPECIALKEY] = (unsigned) ev.special_key;
     data[P_MODIFIERKEYS] = (unsigned) ev.modifierkeys;
     data[P_MODIFIERKEYS] = (unsigned) ev.modifierkeys;
-    data[P_ID] = (unsigned) ev.ref_id;
+    data[P_REFID] = (unsigned) ev.ref_id;
     data[P_TOUCH] = (unsigned) ev.touch;
     data[P_TOUCH] = (unsigned) ev.touch;
 }
 }
 
 
@@ -131,10 +132,88 @@ void UIWidget::Center()
 
 
 }
 }
 
 
+UIWidget* UIWidget::GetParent()
+{
+    if (!widget_)
+        return 0;
+
+    TBWidget* parent = widget_->GetParent();
+
+    if (!parent)
+        return 0;
+
+    UI* ui = GetSubsystem<UI>();
+
+    return ui->WrapWidget(parent);
+
+}
+
+void UIWidget::RemoveChild(UIWidget* child)
+{
+    if (!widget_ || !child)
+        return;
+
+    TBWidget* childw = child->GetInternalWidget();
+
+    if (!childw)
+        return;
+
+    widget_->RemoveChild(childw);
+
+}
+
+
+const String& UIWidget::GetId()
+{
+    if (!widget_ || !widget_->GetID())
+    {
+        if (id_.Length())
+            id_.Clear();
+
+        return id_;
+    }
+
+    if (id_.Length())
+        return id_;
+
+    UI* ui = GetSubsystem<UI>();
+    ui->GetTBIDString(widget_->GetID(), id_);
+
+    return id_;
+
+}
+
 bool UIWidget::OnEvent(const tb::TBWidgetEvent &ev)
 bool UIWidget::OnEvent(const tb::TBWidgetEvent &ev)
 {
 {
+    UI* ui = GetSubsystem<UI>();
+
     if (ev.type == EVENT_TYPE_CLICK)
     if (ev.type == EVENT_TYPE_CLICK)
-        return false;
+    {
+        if (ev.target && ev.target->GetID() == TBID("__popup-menu"))
+        {
+            // popup menu
+
+            if (JSGetHeapPtr())
+            {
+                VariantMap eventData;
+                eventData[PopupMenuSelect::P_BUTTON] = this;
+                eventData[PopupMenuSelect::P_REFID] = (unsigned) ev.ref_id;
+                SendEvent(E_POPUPMENUSELECT, eventData);
+            }
+
+            return true;
+        }
+        else
+        {
+            if (!ev.target || ui->IsWidgetWrapped(ev.target))
+            {
+                VariantMap eventData;
+                ConvertEvent(this, ui->WrapWidget(ev.target), ev, eventData);
+                SendEvent(E_WIDGETEVENT, eventData);
+            }
+        }
+
+    }
 
 
     return false;
     return false;
 }
 }

+ 11 - 1
Source/Atomic/UI/UIWidget.h

@@ -31,8 +31,16 @@ public:
     void SetPosition(int x, int y);
     void SetPosition(int x, int y);
     void SetText(const String& text);
     void SetText(const String& text);
 
 
+    UIWidget* GetParent();
+
+    void RemoveChild(UIWidget* child);
+
+    // String ID
+    const String& GetId();
+
     void Center();
     void Center();
 
 
+    // get this or child widget with id
     UIWidget* GetWidget(const String& id);
     UIWidget* GetWidget(const String& id);
 
 
     void AddChild(UIWidget* child);
     void AddChild(UIWidget* child);
@@ -41,13 +49,15 @@ public:
 
 
 protected:
 protected:
 
 
-    void ConvertEvent(UIWidget* target, const tb::TBWidgetEvent &ev, VariantMap& data);
+    void ConvertEvent(UIWidget* handler, UIWidget* target, const tb::TBWidgetEvent &ev, VariantMap& data);
 
 
     void SetWidget(tb::TBWidget* widget);
     void SetWidget(tb::TBWidget* widget);
 
 
     virtual bool OnEvent(const tb::TBWidgetEvent &ev);
     virtual bool OnEvent(const tb::TBWidgetEvent &ev);
     virtual void OnDelete();
     virtual void OnDelete();
 
 
+    String id_;
+
     tb::TBWidget* widget_;
     tb::TBWidget* widget_;
 
 
 };
 };

+ 1 - 1
Source/Atomic/UI/UIWindow.cpp

@@ -38,7 +38,7 @@ UIWindow::~UIWindow()
 
 
 bool UIWindow::OnEvent(const tb::TBWidgetEvent &ev)
 bool UIWindow::OnEvent(const tb::TBWidgetEvent &ev)
 {
 {
-    return false;
+    return UIWidget::OnEvent(ev);
 }
 }
 
 
 }
 }

+ 3 - 1
Source/AtomicJS/JSBind/modules/UI.json

@@ -2,7 +2,9 @@
 	"name" : "UI",
 	"name" : "UI",
 	"sources" : ["UI"],
 	"sources" : ["UI"],
 	"includes" : ["<Atomic/Graphics/Material.h>", "<Atomic/Scene/Node.h>", "<Atomic/Scene/Scene.h>", "<Atomic/Graphics/Texture2D.h>"],
 	"includes" : ["<Atomic/Graphics/Material.h>", "<Atomic/Scene/Node.h>", "<Atomic/Scene/Scene.h>", "<Atomic/Graphics/Texture2D.h>"],
-	"classes" : ["UIWidget", "UIView", "UIWindow", "UIButton", "UITextField", "UISelectItem", "UISelectItemSource", "UIMenuWindow", "UIEditField"],
+	"classes" : ["UIWidget", "UILayout", "UIView", "UIWindow", "UIButton", "UITextField",
+								"UISelectItem", "UISelectItemSource", "UIMenuWindow", "UIEditField",
+								"UIImageWidget"],
 	"overloads" : {
 	"overloads" : {
 	}
 	}
 }
 }

+ 95 - 18
Source/AtomicJS/Javascript/JSUI.cpp

@@ -128,25 +128,115 @@ void JSUI::HandlePopupMenuSelect(StringHash eventType, VariantMap& eventData)
 
 
 }
 }
 
 
+void JSUI::PushWidgetEventObject(VariantMap& eventData)
+{
+
+    UI* ui = GetSubsystem<UI>();
+
+    using namespace WidgetEvent;
+
+    // create the event object
+    duk_push_object(ctx_);
+
+    // target
+    UIWidget* target = static_cast<UIWidget*>(eventData[P_TARGET].GetPtr());
+
+    if (target)
+    {
+        assert(target->JSGetHeapPtr());
+        duk_push_heapptr(ctx_, target->JSGetHeapPtr());
+    }
+    else
+    {
+        duk_push_null(ctx_);
+    }
+
+    duk_put_prop_string(ctx_, -2, "target");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_TYPE].GetUInt());
+    duk_put_prop_string(ctx_, -2, "type");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_X].GetInt());
+    duk_put_prop_string(ctx_, -2, "x");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_Y].GetInt());
+    duk_put_prop_string(ctx_, -2, "y");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_DELTAX].GetInt());
+    duk_put_prop_string(ctx_, -2, "deltaX");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_DELTAX].GetInt());
+    duk_put_prop_string(ctx_, -2, "deltaY");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_COUNT].GetInt());
+    duk_put_prop_string(ctx_, -2, "count");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_KEY].GetInt());
+    duk_put_prop_string(ctx_, -2, "key");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_SPECIALKEY].GetInt());
+    duk_put_prop_string(ctx_, -2, "specialKey");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_MODIFIERKEYS].GetInt());
+    duk_put_prop_string(ctx_, -2, "modifierKeys");
+
+    duk_push_number(ctx_, (duk_double_t) eventData[P_MODIFIERKEYS].GetInt());
+    duk_put_prop_string(ctx_, -2, "modifierKeys");
+
+    String id;
+    unsigned blah = eventData[P_REFID].GetUInt();
+    ui->GetTBIDString(eventData[P_REFID].GetUInt(), id);
+    duk_push_string(ctx_, id.CString() );
+    duk_put_prop_string(ctx_, -2, "refID");
+
+    duk_push_boolean(ctx_,eventData[P_TOUCH].GetBool() ? 1 : 0);
+    duk_put_prop_string(ctx_, -2, "touch");
+
+}
+
 void JSUI::HandleWidgetEvent(StringHash eventType, VariantMap& eventData)
 void JSUI::HandleWidgetEvent(StringHash eventType, VariantMap& eventData)
 {
 {
     using namespace WidgetEvent;
     using namespace WidgetEvent;
 
 
-    UIWidget* widget = static_cast<UIWidget*>(eventData[P_TARGET].GetPtr());
-    if (!widget)
+    UIWidget* handler = static_cast<UIWidget*>(eventData[P_HANDLER].GetPtr());
+    UIWidget* target = static_cast<UIWidget*>(eventData[P_TARGET].GetPtr());
+
+    if (!handler)
         return;
         return;
 
 
-    void* heapptr = widget->JSGetHeapPtr();
+    void* handlerHeapPtr = handler->JSGetHeapPtr();
 
 
-    if (!heapptr)
+    if (!handlerHeapPtr)
+        return;
+
+    // if we have a target, however no corresponding JS object return
+    if (target && !target->JSGetHeapPtr())
         return;
         return;
 
 
     tb::EVENT_TYPE type = (tb::EVENT_TYPE) eventData[P_TYPE].GetUInt();
     tb::EVENT_TYPE type = (tb::EVENT_TYPE) eventData[P_TYPE].GetUInt();
 
 
+    // general event handler, bubbles to (wrapped) parent widgets unless handled (returns true)
     if (type == tb::EVENT_TYPE_CLICK)
     if (type == tb::EVENT_TYPE_CLICK)
     {
     {
         int top = duk_get_top(ctx_);
         int top = duk_get_top(ctx_);
-        duk_push_heapptr(ctx_, heapptr);
+        duk_push_heapptr(ctx_, handlerHeapPtr);
+        duk_get_prop_string(ctx_, -1, "onEvent");
+        if (duk_is_callable(ctx_, -1)) {
+
+            PushWidgetEventObject(eventData);
+
+            duk_call(ctx_, 1);
+        }
+        duk_pop_n(ctx_, 2);
+        assert(top == duk_get_top(ctx_));
+    }
+
+    // specific event handlers
+
+    if (type == tb::EVENT_TYPE_CLICK)
+    {
+        int top = duk_get_top(ctx_);
+        duk_push_heapptr(ctx_, handlerHeapPtr);
         duk_get_prop_string(ctx_, -1, "onClick");
         duk_get_prop_string(ctx_, -1, "onClick");
         if (duk_is_callable(ctx_, -1)) {
         if (duk_is_callable(ctx_, -1)) {
             duk_call(ctx_, 0);
             duk_call(ctx_, 0);
@@ -156,19 +246,6 @@ void JSUI::HandleWidgetEvent(StringHash eventType, VariantMap& eventData)
         return;
         return;
     }
     }
 
 
-    eventData[P_TYPE];
-    eventData[P_X];
-    eventData[P_Y];
-    eventData[P_DELTAX];
-    eventData[P_DELTAY];
-    eventData[P_COUNT];
-    eventData[P_KEY];
-    eventData[P_SPECIALKEY];
-    eventData[P_MODIFIERKEYS];
-    eventData[P_ID];
-    eventData[P_TOUCH];
-
-
 }
 }
 
 
 }
 }

+ 2 - 0
Source/AtomicJS/Javascript/JSUI.h

@@ -25,6 +25,8 @@ private:
 
 
     duk_context* ctx_;
     duk_context* ctx_;
 
 
+    void PushWidgetEventObject(VariantMap& eventData);
+
     void HandleWidgetEvent(StringHash eventType, VariantMap& eventData);
     void HandleWidgetEvent(StringHash eventType, VariantMap& eventData);
     void HandleWidgetLoaded(StringHash eventType, VariantMap& eventData);
     void HandleWidgetLoaded(StringHash eventType, VariantMap& eventData);
     void HandlePopupMenuSelect(StringHash eventType, VariantMap& eventData);
     void HandlePopupMenuSelect(StringHash eventType, VariantMap& eventData);

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

@@ -343,6 +343,7 @@ enum WIDGET_HIT_STATUS {
 	WIDGET_HIT_STATUS_HIT_NO_CHILDREN		///< The widget was hit, no children should be hit.
 	WIDGET_HIT_STATUS_HIT_NO_CHILDREN		///< The widget was hit, no children should be hit.
 };
 };
 
 
+// ATOMIC: this must only be used by UIWidget, as we are casting to it
 class TBWidgetDelegate
 class TBWidgetDelegate
 {
 {
 public:
 public:

+ 1 - 1
Source/ThirdParty/TurboBadger/tb_window.cpp

@@ -226,7 +226,7 @@ bool TBWindow::OnEvent(const TBWidgetEvent &ev)
 			Close();
 			Close();
 		return true;
 		return true;
 	}
 	}
-	return false;
+    return TBWidget::OnEvent(ev);
 }
 }
 
 
 void TBWindow::OnAdded()
 void TBWindow::OnAdded()