Browse Source

New UI Work

Josh Engebretson 10 years ago
parent
commit
fe3df36e13

+ 20 - 3
Source/Atomic/UI/UI.cpp

@@ -43,7 +43,7 @@ void TBSystem::RescheduleTimer(double fire_time)
 namespace Atomic
 namespace Atomic
 {
 {
 
 
-WeakPtr<Context> UI::readerContext_;
+WeakPtr<Context> UI::uiContext_;
 
 
 
 
 UI::UI(Context* context) :
 UI::UI(Context* context) :
@@ -67,6 +67,11 @@ UI::~UI()
         tb_core_shutdown();
         tb_core_shutdown();
     }
     }
 
 
+    uiContext_ = 0;
+    TBFile::SetReaderFunction(0);
+    TBID::tbidRegisterCallback = 0;
+
+
 }
 }
 
 
 void UI::Shutdown()
 void UI::Shutdown()
@@ -83,8 +88,10 @@ void UI::Initialize(const String& languageFile)
 
 
     vertexBuffer_ = new VertexBuffer(context_);
     vertexBuffer_ = new VertexBuffer(context_);
 
 
-    readerContext_ = context_;
+    uiContext_ = context_;
+
     TBFile::SetReaderFunction(TBFileReader);
     TBFile::SetReaderFunction(TBFileReader);
+    TBID::tbidRegisterCallback = UI::TBIDRegisterStringCallback;
 
 
     TBWidgetsAnimationManager::Init();
     TBWidgetsAnimationManager::Init();
 
 
@@ -306,7 +313,7 @@ void UI::TBFileReader(const char* filename, void** data, unsigned* length)
     *data = 0;
     *data = 0;
     *length = 0;
     *length = 0;
 
 
-    ResourceCache* cache = readerContext_->GetSubsystem<ResourceCache>();
+    ResourceCache* cache = uiContext_->GetSubsystem<ResourceCache>();
     SharedPtr<File> file = cache->GetFile(filename);
     SharedPtr<File> file = cache->GetFile(filename);
     if (!file || !file->IsOpen())
     if (!file || !file->IsOpen())
         return;
         return;
@@ -331,6 +338,16 @@ void UI::TBFileReader(const char* filename, void** data, unsigned* length)
 
 
 }
 }
 
 
+void UI::GetTBIDString(unsigned id, String& value)
+{
+    value = tbidToString_[id];
+}
+
+void UI::TBIDRegisterStringCallback(unsigned id, const char* value)
+{
+    uiContext_->GetSubsystem<UI>()->tbidToString_[id] = String(value);
+}
+
 bool UI::LoadResourceFile(TBWidget* widget, const String& filename)
 bool UI::LoadResourceFile(TBWidget* widget, const String& filename)
 {
 {
 
 

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

@@ -47,10 +47,13 @@ public:
 
 
     UIWidget* WrapWidget(tb::TBWidget* widget);
     UIWidget* WrapWidget(tb::TBWidget* widget);
 
 
+    void GetTBIDString(unsigned id, String& value);
+
 private:
 private:
 
 
-    static WeakPtr<Context> readerContext_;
+    static WeakPtr<Context> uiContext_;
     static void TBFileReader(const char* filename, void** data, unsigned* length);
     static void TBFileReader(const char* filename, void** data, unsigned* length);
+    static void TBIDRegisterStringCallback(unsigned id, const char* value);
 
 
     void HandleRenderUpdate(StringHash eventType, VariantMap& eventData);
     void HandleRenderUpdate(StringHash eventType, VariantMap& eventData);
     void Render(VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigned batchStart, unsigned batchEnd);
     void Render(VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigned batchStart, unsigned batchEnd);
@@ -68,6 +71,7 @@ private:
     WeakPtr<Graphics> graphics_;
     WeakPtr<Graphics> graphics_;
 
 
     HashMap<tb::TBWidget*, UIWidget*> widgetWrap_;
     HashMap<tb::TBWidget*, UIWidget*> widgetWrap_;
+    HashMap<unsigned, String> tbidToString_;
 
 
     bool inputDisabled_;
     bool inputDisabled_;
     bool keyboardDisabled_;
     bool keyboardDisabled_;

+ 27 - 9
Source/Atomic/UI/UIButton.cpp

@@ -25,15 +25,33 @@ UIButton::~UIButton()
 }
 }
 
 
 bool UIButton::OnEvent(const tb::TBWidgetEvent &ev)
 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);
-
-        // this is catching the window close button
-        return true;
+{       
+    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 false;

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

@@ -48,6 +48,13 @@ EVENT(E_WIDGETLOADED, WidgetLoaded)
     PARAM(P_WIDGET, Widget);             // UIWidget pointer
     PARAM(P_WIDGET, Widget);             // UIWidget pointer
 }
 }
 
 
+EVENT(E_POPUPMENUSELECT, PopupMenuSelect)
+{
+    PARAM(P_BUTTON, Button);             // UIButton that created popup
+    PARAM(P_REFID, RefID);             // unsigned tbid
+}
+
+
 /// Mouse click in the UI.
 /// Mouse click in the UI.
 EVENT(E_UIMOUSECLICK, UIMouseClick)
 EVENT(E_UIMOUSECLICK, UIMouseClick)
 {
 {

+ 2 - 0
Source/AtomicJS/Javascript/JSAtomic.cpp

@@ -15,6 +15,7 @@
 #include "JSVM.h"
 #include "JSVM.h"
 #include "JSComponent.h"
 #include "JSComponent.h"
 #include "JSGraphics.h"
 #include "JSGraphics.h"
+#include "JSUIAPI.h"
 #include "JSScene.h"
 #include "JSScene.h"
 
 
 #include "JSAtomicGame.h"
 #include "JSAtomicGame.h"
@@ -206,6 +207,7 @@ void jsapi_init_atomic(JSVM* vm)
 
 
     // extensions
     // extensions
     jsapi_init_graphics(vm);
     jsapi_init_graphics(vm);
+    jsapi_init_ui(vm);
     jsapi_init_scene(vm);
     jsapi_init_scene(vm);
 
 
     jsapi_init_atomicgame(vm);
     jsapi_init_atomicgame(vm);

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

@@ -2,6 +2,7 @@
 
 
 #include <Atomic/UI/UIEvents.h>
 #include <Atomic/UI/UIEvents.h>
 #include <Atomic/UI/UIWidget.h>
 #include <Atomic/UI/UIWidget.h>
+#include <Atomic/UI/UIButton.h>
 #include <Atomic/UI/UI.h>
 #include <Atomic/UI/UI.h>
 #include "JSVM.h"
 #include "JSVM.h"
 #include "JSUI.h"
 #include "JSUI.h"
@@ -16,6 +17,7 @@ JSUI::JSUI(Context* context) : Object(context)
     ctx_ = JSVM::GetJSVM(nullptr)->GetJSContext();
     ctx_ = JSVM::GetJSVM(nullptr)->GetJSContext();
     SubscribeToEvent(E_WIDGETEVENT, HANDLER(JSUI, HandleWidgetEvent));
     SubscribeToEvent(E_WIDGETEVENT, HANDLER(JSUI, HandleWidgetEvent));
     SubscribeToEvent(E_WIDGETLOADED, HANDLER(JSUI, HandleWidgetLoaded));
     SubscribeToEvent(E_WIDGETLOADED, HANDLER(JSUI, HandleWidgetLoaded));
+    SubscribeToEvent(E_POPUPMENUSELECT, HANDLER(JSUI, HandlePopupMenuSelect));
 }
 }
 
 
 JSUI::~JSUI()
 JSUI::~JSUI()
@@ -84,6 +86,48 @@ void JSUI::HandleWidgetLoaded(StringHash eventType, VariantMap& eventData)
 
 
 }
 }
 
 
+void JSUI::HandlePopupMenuSelect(StringHash eventType, VariantMap& eventData)
+{
+    using namespace PopupMenuSelect;
+
+    UIButton* button = static_cast<UIButton*>(eventData[P_BUTTON].GetPtr());
+    if (!button)
+        return;
+
+    void* heapptr = button->JSGetHeapPtr();
+
+    if (!heapptr) // gc'd
+        return;
+
+    int top = duk_get_top(ctx_);
+
+    duk_push_heapptr(ctx_, heapptr);
+    duk_get_prop_string(ctx_, -1, "__popup_menu_callback");
+    if (!duk_is_callable(ctx_, -1))
+    {
+        duk_pop_n(ctx_, 2);
+        assert(top == duk_get_top(ctx_));
+        return;
+    }
+
+    UI* ui = GetSubsystem<UI>();
+    String id;
+    ui->GetTBIDString(eventData[P_REFID].GetUInt(), id);
+
+    duk_push_string(ctx_, id.CString());
+    duk_insert(ctx_, -1);
+
+    if (duk_pcall(ctx_, 1) != 0)
+    {
+        JSVM::GetJSVM(nullptr)->SendJSErrorEvent();
+    }
+
+    duk_pop_n(ctx_, 2);
+
+    assert(top == duk_get_top(ctx_));
+
+}
+
 void JSUI::HandleWidgetEvent(StringHash eventType, VariantMap& eventData)
 void JSUI::HandleWidgetEvent(StringHash eventType, VariantMap& eventData)
 {
 {
     using namespace WidgetEvent;
     using namespace WidgetEvent;

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

@@ -27,6 +27,7 @@ private:
 
 
     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 GatherWidgets(tb::TBWidget* widget, PODVector<tb::TBWidget*>& widgets);
     void GatherWidgets(tb::TBWidget* widget, PODVector<tb::TBWidget*>& widgets);
 
 

+ 87 - 0
Source/AtomicJS/Javascript/JSUIAPI.cpp

@@ -0,0 +1,87 @@
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// Please see LICENSE.md in repository root for license information
+// https://github.com/AtomicGameEngine/AtomicGameEngine
+
+#include "JSUIAPI.h"
+#include "JSVM.h"
+
+#include <Atomic/UI/UISelectItem.h>
+#include <Atomic/UI/UIMenuWindow.h>
+#include <Atomic/UI/UIButton.h>
+
+namespace Atomic
+{
+
+static int UIButton_Popup(duk_context* ctx)
+{
+
+    if (!duk_is_object(ctx, 0))
+    {
+        duk_push_string(ctx, "UIButton.popup first argument must be an object");
+        duk_throw(ctx);
+    }
+    if (!duk_is_callable(ctx, 1))
+    {
+        duk_push_string(ctx, "UIButton.popup second argument must be callable");
+        duk_throw(ctx);
+    }
+
+    JSVM* vm = JSVM::GetJSVM(ctx);
+
+    duk_enum(ctx, 0, DUK_ENUM_OWN_PROPERTIES_ONLY);
+
+    UISelectItemSource* source = new UISelectItemSource(vm->GetContext());
+
+    while (duk_next(ctx, -1, 0)) {
+
+        String key = duk_get_string(ctx, -1);
+
+        duk_get_prop(ctx, 0);
+
+        if (duk_is_array(ctx, -1))
+        {
+            // need to support this, for skin image, etc
+            assert(0);
+        }
+        else if (duk_is_string(ctx, -1))
+        {
+            // id
+            String id = duk_get_string(ctx, -1);            
+            source->AddItem(new UISelectItem(vm->GetContext(), key, id));
+        }
+        else
+        {
+            duk_push_string(ctx, "UIButton.popup data object key is not an array or string");
+            duk_throw(ctx);
+        }
+
+        duk_pop(ctx);  // pop key value
+    }
+
+    duk_pop(ctx);  // pop enum object
+
+    duk_push_this(ctx);
+
+    duk_dup(ctx, 1);
+    duk_put_prop_string(ctx, -2, "__popup_menu_callback");
+
+    UIButton* button = js_to_class_instance<UIButton>(ctx, -1, 0);
+    UIMenuWindow* menuWindow = new UIMenuWindow(vm->GetContext(), button, "__popup-menu");
+    menuWindow->Show(source);
+    duk_pop(ctx);
+
+    return 0;
+}
+
+void jsapi_init_ui(JSVM* vm)
+{
+    duk_context* ctx = vm->GetJSContext();
+
+    js_class_get_prototype(ctx, "UIButton");
+    duk_push_c_function(ctx, UIButton_Popup, 2);
+    duk_put_prop_string(ctx, -2, "popup");
+    duk_pop(ctx);
+
+}
+
+}

+ 16 - 0
Source/AtomicJS/Javascript/JSUIAPI.h

@@ -0,0 +1,16 @@
+// Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
+// Please see LICENSE.md in repository root for license information
+// https://github.com/AtomicGameEngine/AtomicGameEngine
+
+#pragma once
+
+#include "JSAPI.h"
+
+namespace Atomic
+{
+
+class JSVM;
+
+void jsapi_init_ui(JSVM* vm);
+
+}

+ 4 - 0
Source/ThirdParty/TurboBadger/tb_id.cpp

@@ -8,6 +8,8 @@
 
 
 namespace tb {
 namespace tb {
 
 
+TBIDRegisterStringCallback TBID::tbidRegisterCallback = nullptr;
+
 // == TBID ==============================================================================
 // == TBID ==============================================================================
 
 
 #ifdef TB_RUNTIME_DEBUG_INFO
 #ifdef TB_RUNTIME_DEBUG_INFO
@@ -67,6 +69,8 @@ void TBID::Set(const char *string)
 		{
 		{
 			is_adding = true;
 			is_adding = true;
 			all_id_hash.Add(id, new TBID(*this));
 			all_id_hash.Add(id, new TBID(*this));
+            if (tbidRegisterCallback)
+                tbidRegisterCallback(id, string);
 			is_adding = false;
 			is_adding = false;
 		}
 		}
 	}
 	}

+ 4 - 0
Source/ThirdParty/TurboBadger/tb_id.h

@@ -12,6 +12,8 @@
 
 
 namespace tb {
 namespace tb {
 
 
+typedef void (*TBIDRegisterStringCallback) (uint32 id, const char* string);
+
 /** TBID is a wrapper for a uint32 to be used as ID.
 /** TBID is a wrapper for a uint32 to be used as ID.
 	The uint32 can be set directly to any uint32, or it can be
 	The uint32 can be set directly to any uint32, or it can be
 	set from a string which will be hashed into the uint32. */
 	set from a string which will be hashed into the uint32. */
@@ -43,6 +45,8 @@ public:
 	friend class TBLanguage;
 	friend class TBLanguage;
 	TBStr debug_string;
 	TBStr debug_string;
 #endif
 #endif
+
+    static TBIDRegisterStringCallback tbidRegisterCallback;
 };
 };
 
 
 }; // namespace tb
 }; // namespace tb