Browse Source

Work on New UI

Josh Engebretson 10 years ago
parent
commit
80b8802b53

+ 26 - 2
Source/Atomic/UI/UI.cpp

@@ -26,6 +26,8 @@ using namespace tb;
 
 #include "UIRenderer.h"
 #include "UI.h"
+#include "UIButton.h"
+#include "UITextField.h"
 
 namespace tb
 {
@@ -349,12 +351,34 @@ void UI::HandleScreenMode(StringHash eventType, VariantMap& eventData)
     //SetSize(eventData[P_WIDTH].GetInt(), eventData[P_HEIGHT].GetInt());
 }
 
-
-
 void UI::HandleUpdate(StringHash eventType, VariantMap& eventData)
 {
     TBMessageHandler::ProcessMessages();
 }
 
+UIWidget* UI::WrapWidget(tb::TBWidget* widget)
+{
+    if (widgetWrap_.Contains(widget))
+        return widgetWrap_[widget];
+
+    if (widget->IsOfType<TBButton>())
+    {
+        UIButton* button = new UIButton(context_, false);
+        button->SetWidget(widget);
+        widgetWrap_[widget] = button;
+        return button;
+    }
+
+    if (widget->IsOfType<TBTextField>())
+    {
+        UITextField* textfield = new UITextField(context_, false);
+        textfield->SetWidget(widget);
+        widgetWrap_[widget] = textfield;
+        return textfield;
+    }
+
+    return 0;
+}
+
 
 }

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

@@ -14,6 +14,7 @@ namespace Atomic
 
 class VertexBuffer;
 class UIRenderer;
+class UIWidget;
 
 class UI : public Object
 {
@@ -44,6 +45,8 @@ public:
     void AddFont(const String& fontFile, const String &name);
     void SetDefaultFont(const String& name, int size);
 
+    UIWidget* WrapWidget(tb::TBWidget* widget);
+
 private:
 
     static WeakPtr<Context> readerContext_;
@@ -64,6 +67,8 @@ private:
 
     WeakPtr<Graphics> graphics_;
 
+    HashMap<tb::TBWidget*, UIWidget*> widgetWrap_;
+
     bool inputDisabled_;
     bool keyboardDisabled_;
     bool initialized_;

+ 40 - 0
Source/Atomic/UI/UIButton.cpp

@@ -0,0 +1,40 @@
+
+#include <TurboBadger/tb_widgets.h>
+#include <TurboBadger/tb_widgets_common.h>
+
+#include "UIEvents.h"
+#include "UIButton.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+UIButton::UIButton(Context* context, bool createWidget) : UIWidget(context, false)
+{
+    if (createWidget)
+    {
+        widget_ = new TBButton();
+        widget_->SetDelegate(this);
+    }
+}
+
+UIButton::~UIButton()
+{
+
+}
+
+bool UIButton::OnEvent(const tb::TBWidgetEvent &ev)
+{
+    if (ev.type == EVENT_TYPE_CLICK && ev.target == widget_)
+    {
+        VariantMap eventData;
+        ConvertEvent(this, ev, eventData);
+        SendEvent(E_WIDGETEVENT, eventData);
+        return true;
+    }
+
+    return false;
+}
+
+}

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

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

+ 16 - 0
Source/Atomic/UI/UIEvents.h

@@ -27,6 +27,22 @@
 namespace Atomic
 {
 
+EVENT(E_WIDGETEVENT, WidgetEvent)
+{
+    PARAM(P_TARGET, Target);             // UIWidget pointer
+    PARAM(P_TYPE, Type);                 // EVENT_TYPE enum
+    PARAM(P_X, X);                       // int
+    PARAM(P_Y, Y);                       // int
+    PARAM(P_DELTAX, DeltaX);             // int
+    PARAM(P_DELTAY, DeltaY);             // int
+    PARAM(P_COUNT, Count);               // int
+    PARAM(P_KEY, Key);                   // int
+    PARAM(P_SPECIALKEY, SpecialKey);     // enum SPECIAL_KEY
+    PARAM(P_MODIFIERKEYS, ModifierKeys); // enum MODIFIER_KEYS
+    PARAM(P_ID, ID);                     // unsigned (TBID)
+    PARAM(P_TOUCH, Touch);               // bool
+}
+
 /// Mouse click in the UI.
 EVENT(E_UIMOUSECLICK, UIMouseClick)
 {

+ 32 - 0
Source/Atomic/UI/UITextField.cpp

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

+ 26 - 0
Source/Atomic/UI/UITextField.h

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

+ 32 - 0
Source/Atomic/UI/UIView.cpp

@@ -0,0 +1,32 @@
+
+#include <TurboBadger/tb_widgets.h>
+
+#include "UI.h"
+#include "UIView.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+UIView::UIView(Context* context) : UIWidget(context, false)
+{
+    widget_ = new TBWidget();
+    widget_->SetDelegate(this);
+
+    UI* ui = GetSubsystem<UI>();
+
+    TBRect rect = ui->GetRootWidget()->GetRect();
+    widget_->SetSize(rect.w, rect.h);
+
+    ui->GetRootWidget()->AddChild(widget_);
+
+}
+
+UIView::~UIView()
+{
+
+}
+
+
+}

+ 25 - 0
Source/Atomic/UI/UIView.h

@@ -0,0 +1,25 @@
+
+#pragma once
+
+#include "UIWidget.h"
+
+namespace Atomic
+{
+
+/// a view off the root widget
+class UIView : public UIWidget
+{
+    OBJECT(UIView)
+
+public:
+
+    UIView(Context* context);
+    virtual ~UIView();
+
+protected:
+
+private:
+
+};
+
+}

+ 109 - 0
Source/Atomic/UI/UIWidget.cpp

@@ -0,0 +1,109 @@
+
+//--player --editor-resource-paths "/Users/josh/Dev/atomic/AtomicGameEngine/Data/AtomicPlayer/Resources/CoreData!/Users/josh/Dev/atomic/AtomicGameEngine/Data/AtomicPlayer/Resources/PlayerData!/Users/josh/Dev/atomic/AtomicExamples/UIExample/Resources"
+
+#include "../IO/Log.h"
+
+#include "UIEvents.h"
+#include "UI.h"
+#include "UIWidget.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+UIWidget::UIWidget(Context* context, bool createWidget) : Object(context),
+    widget_(0)
+{    
+    AddRef();
+
+    if (createWidget)
+    {
+        widget_ = new TBWidget();
+        widget_->SetDelegate(this);
+    }
+}
+
+UIWidget::~UIWidget()
+{
+
+}
+
+bool UIWidget::Load(const String& filename)
+{
+    UI* ui = GetSubsystem<UI>();
+
+    if  (!ui->LoadResourceFile(widget_ , filename))
+        return false;
+
+    return true;
+}
+
+UIWidget* UIWidget::GetWidgetByID(const String& id)
+{
+    if (!widget_)
+        return 0;
+
+    TBWidget* child = widget_->GetWidgetByID(TBID(id.CString()));
+
+    if (!child)
+        return 0;
+
+    UI* ui = GetSubsystem<UI>();
+    return ui->WrapWidget(child);
+}
+
+void UIWidget::SetWidget(tb::TBWidget* widget)
+{
+    widget_ = widget;
+    widget_->SetDelegate(this);
+}
+
+void UIWidget::ConvertEvent(UIWidget* target, const tb::TBWidgetEvent &ev, VariantMap& data)
+{
+    using namespace WidgetEvent;
+    data[P_TARGET] = target;
+    data[P_TYPE] = (unsigned) ev.type;
+    data[P_X] = ev.target_x;
+    data[P_Y] = ev.target_y;
+    data[P_DELTAX] = ev.delta_x;
+    data[P_DELTAY] = ev.delta_y;
+    data[P_COUNT] = ev.count;
+    data[P_KEY] = ev.key;
+    data[P_SPECIALKEY] = (unsigned) ev.special_key;
+    data[P_MODIFIERKEYS] = (unsigned) ev.modifierkeys;
+    data[P_ID] = (unsigned) ev.ref_id;
+    data[P_TOUCH] = (unsigned) ev.touch;
+}
+
+void UIWidget::OnDelete()
+{
+    widget_ = 0;
+    ReleaseRef();
+}
+
+void UIWidget::AddChild(UIWidget* child)
+{
+    if (!widget_ || !child->widget_)
+        return;
+
+    widget_->AddChild(child->widget_);
+}
+
+bool UIWidget::SetText(const String& text)
+{
+    if (!widget_)
+        return false;
+
+    return widget_->SetText(text.CString());
+}
+
+void UIWidget::SetSize(int width, int height)
+{
+    if (!widget_)
+        return;
+
+    widget_->SetSize(width, height);
+}
+
+}

+ 50 - 0
Source/Atomic/UI/UIWidget.h

@@ -0,0 +1,50 @@
+
+#pragma once
+
+#include <TurboBadger/tb_widgets.h>
+#include "../Core/Object.h"
+
+namespace tb
+{
+class TBWidget;
+}
+
+
+namespace Atomic
+{
+
+/// Wraps a TurboBadger widget
+class UIWidget : public Object, public tb::TBWidgetDelegate
+{
+    friend class UI;
+
+    OBJECT(UIWidget)
+
+public:
+
+    UIWidget(Context* context, bool createWidget = true);
+    virtual ~UIWidget();
+
+    bool Load(const String& filename);
+
+    void SetSize(int width, int height);
+    bool SetText(const String& text);
+
+    UIWidget* GetWidgetByID(const String& id);
+
+    void AddChild(UIWidget* child);
+
+protected:
+
+    void ConvertEvent(UIWidget* target, const tb::TBWidgetEvent &ev, VariantMap& data);
+
+    void SetWidget(tb::TBWidget* widget);
+
+    virtual bool OnEvent(const tb::TBWidgetEvent &ev) { return false; }
+    virtual void OnDelete();
+
+    tb::TBWidget* widget_;
+
+};
+
+}

+ 44 - 0
Source/Atomic/UI/UIWindow.cpp

@@ -0,0 +1,44 @@
+
+#include <TurboBadger/tb_widgets.h>
+#include <TurboBadger/tb_widgets_common.h>
+#include <TurboBadger/tb_window.h>
+
+#include "../IO/Log.h"
+
+#include "UIEvents.h"
+#include "UIWindow.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+UIWindow::UIWindow(Context* context, bool createWidget) : UIWidget(context, false)
+{
+    if (createWidget)
+    {
+        widget_ = new TBWindow();
+        widget_->SetDelegate(this);
+    }
+}
+
+void UIWindow::ResizeToFitContent()
+{
+    if (!widget_)
+        return;
+
+    ((TBWindow*)widget_)->ResizeToFitContent();
+
+}
+
+UIWindow::~UIWindow()
+{
+
+}
+
+bool UIWindow::OnEvent(const tb::TBWidgetEvent &ev)
+{
+    return false;
+}
+
+}

+ 29 - 0
Source/Atomic/UI/UIWindow.h

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

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

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

+ 65 - 0
Source/AtomicJS/Javascript/JSUI.cpp

@@ -0,0 +1,65 @@
+#include <TurboBadger/tb_widgets.h>
+
+#include <Atomic/UI/UIEvents.h>
+#include <Atomic/UI/UIWidget.h>
+#include "JSVM.h"
+#include "JSUI.h"
+
+namespace Atomic
+{
+
+JSUI::JSUI(Context* context) : Object(context)
+{
+    ctx_ = JSVM::GetJSVM(nullptr)->GetJSContext();
+    SubscribeToEvent(E_WIDGETEVENT, HANDLER(JSUI, HandleWidgetEvent));
+}
+
+JSUI::~JSUI()
+{
+
+}
+
+void JSUI::HandleWidgetEvent(StringHash eventType, VariantMap& eventData)
+{
+    using namespace WidgetEvent;
+
+    UIWidget* widget = static_cast<UIWidget*>(eventData[P_TARGET].GetPtr());
+    if (!widget)
+        return;
+
+    void* heapptr = widget->JSGetHeapPtr();
+
+    if (!heapptr)
+        return;
+
+    tb::EVENT_TYPE type = (tb::EVENT_TYPE) eventData[P_TYPE].GetUInt();
+
+    if (type == tb::EVENT_TYPE_CLICK)
+    {
+        int top = duk_get_top(ctx_);
+        duk_push_heapptr(ctx_, heapptr);
+        duk_get_prop_string(ctx_, -1, "onClick");
+        if (duk_is_callable(ctx_, -1)) {
+            duk_call(ctx_, 0);
+        }
+        duk_pop_n(ctx_, 2);
+        assert(top == duk_get_top(ctx_));
+        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];
+
+
+}
+
+}

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

@@ -0,0 +1,28 @@
+
+#pragma once
+
+#include <Duktape/duktape.h>
+#include <Atomic/Core/Object.h>
+
+namespace Atomic
+{
+
+class JSUI : public Object
+{
+    OBJECT(JSUI)
+
+public:
+
+    JSUI(Context* context);
+    virtual ~JSUI();
+
+private:
+
+    duk_context* ctx_;
+
+    void HandleWidgetEvent(StringHash eventType, VariantMap& eventData);
+
+
+};
+
+}

+ 3 - 0
Source/AtomicJS/Javascript/JSVM.cpp

@@ -17,6 +17,7 @@
 #include "JSEvents.h"
 #include "JSVM.h"
 #include "JSAtomic.h"
+#include "JSUI.h"
 
 namespace Atomic
 {
@@ -63,6 +64,8 @@ void JSVM::InitJSContext()
 
     InitComponents();
 
+    ui_ = new JSUI(context_);
+
     // handle this elsewhere?
     SubscribeToEvents();
 

+ 4 - 3
Source/AtomicJS/Javascript/JSVM.h

@@ -18,6 +18,7 @@ namespace Atomic
 {
 
 class JSFile;
+class JSUI;
 
 class ATOMIC_API JSVM : public Object
 {
@@ -35,8 +36,8 @@ public:
 
     // Resources/Scripts/*.js
     bool ExecuteScript(const String& scriptPath);
-    // Resources/Script/main.js
 
+    // Resources/Script/main.js
     // Catches not requiring AtomicGame, etc
     bool ExecuteMain();
 
@@ -148,8 +149,6 @@ private:
 
 #endif
 
-    List<Object*> jsObjects_;
-
     float gcTime_;
 
     String moduleSearchPath_;
@@ -157,6 +156,8 @@ private:
 
     String errorString_;
 
+    SharedPtr<JSUI> ui_;
+
     static JSVM* instance_;
 
 };

+ 5 - 1
Source/ThirdParty/TurboBadger/tb_widgets.cpp

@@ -70,7 +70,8 @@ TBWidget::TBWidget()
 	, m_gravity(WIDGET_GRAVITY_DEFAULT)
 	, m_layout_params(nullptr)
 	, m_scroller(nullptr)
-	, m_long_click_timer(nullptr)
+    , m_long_click_timer(nullptr)
+    , m_delegate(nullptr)
 	, m_packed_init(0)
 {
 #ifdef TB_RUNTIME_DEBUG_INFO
@@ -91,6 +92,9 @@ TBWidget::~TBWidget()
 	if (this == focused_widget)
 		focused_widget = nullptr;
 
+    if (m_delegate)
+        m_delegate->OnDelete();
+
 	TBWidgetListener::InvokeWidgetDelete(this);
 	DeleteAllChildren();
 

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

@@ -343,6 +343,14 @@ enum WIDGET_HIT_STATUS {
 	WIDGET_HIT_STATUS_HIT_NO_CHILDREN		///< The widget was hit, no children should be hit.
 };
 
+class TBWidgetDelegate
+{
+public:
+    virtual bool OnEvent(const TBWidgetEvent &ev) = 0;
+
+    virtual void OnDelete() = 0;
+};
+
 /** The base TBWidget class.
 	Make a subclass to implement UI controls.
 	Each widget has a background skin (no skin specified by default) which will be used to
@@ -600,6 +608,9 @@ public:
 		events are going through this widget (See GetEventDestination()) */
 	bool IsEventDestinationFor(TBWidget *other_widget) const;
 
+    TBWidgetDelegate* GetDelegate() {return m_delegate; }
+    void SetDelegate(TBWidgetDelegate* delegate) { m_delegate = delegate; }
+
 	// == Callbacks ==============================================
 
 	/** Add a listener to this widget. It should be removed again with
@@ -611,7 +622,7 @@ public:
 	/** Callback for handling events.
 		Return true if the event is handled and should not
 		continue to be handled by any parent widgets. */
-	virtual bool OnEvent(const TBWidgetEvent &ev) { return false; }
+    virtual bool OnEvent(const TBWidgetEvent &ev) { if (m_delegate) return m_delegate->OnEvent(ev); return false; }
 
 	/** Callback for doing anything that might be needed before paint.
 		F.ex Updating invalid layout, formatting text etc. */
@@ -994,6 +1005,7 @@ private:
 	LayoutParams *m_layout_params;	///< Layout params, or nullptr.
 	TBScroller *m_scroller;
 	TBLongClickTimer *m_long_click_timer;
+    TBWidgetDelegate* m_delegate;
 	union {
 		struct {
 			uint16 is_group_root : 1;