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
 {
 
-WeakPtr<Context> UI::readerContext_;
+WeakPtr<Context> UI::uiContext_;
 
 
 UI::UI(Context* context) :
@@ -67,6 +67,11 @@ UI::~UI()
         tb_core_shutdown();
     }
 
+    uiContext_ = 0;
+    TBFile::SetReaderFunction(0);
+    TBID::tbidRegisterCallback = 0;
+
+
 }
 
 void UI::Shutdown()
@@ -83,8 +88,10 @@ void UI::Initialize(const String& languageFile)
 
     vertexBuffer_ = new VertexBuffer(context_);
 
-    readerContext_ = context_;
+    uiContext_ = context_;
+
     TBFile::SetReaderFunction(TBFileReader);
+    TBID::tbidRegisterCallback = UI::TBIDRegisterStringCallback;
 
     TBWidgetsAnimationManager::Init();
 
@@ -306,7 +313,7 @@ void UI::TBFileReader(const char* filename, void** data, unsigned* length)
     *data = 0;
     *length = 0;
 
-    ResourceCache* cache = readerContext_->GetSubsystem<ResourceCache>();
+    ResourceCache* cache = uiContext_->GetSubsystem<ResourceCache>();
     SharedPtr<File> file = cache->GetFile(filename);
     if (!file || !file->IsOpen())
         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)
 {
 

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

@@ -47,10 +47,13 @@ public:
 
     UIWidget* WrapWidget(tb::TBWidget* widget);
 
+    void GetTBIDString(unsigned id, String& value);
+
 private:
 
-    static WeakPtr<Context> readerContext_;
+    static WeakPtr<Context> uiContext_;
     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 Render(VertexBuffer* buffer, const PODVector<UIBatch>& batches, unsigned batchStart, unsigned batchEnd);
@@ -68,6 +71,7 @@ private:
     WeakPtr<Graphics> graphics_;
 
     HashMap<tb::TBWidget*, UIWidget*> widgetWrap_;
+    HashMap<unsigned, String> tbidToString_;
 
     bool inputDisabled_;
     bool keyboardDisabled_;

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

@@ -25,15 +25,33 @@ 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);
-
-        // 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;

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

@@ -48,6 +48,13 @@ EVENT(E_WIDGETLOADED, WidgetLoaded)
     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.
 EVENT(E_UIMOUSECLICK, UIMouseClick)
 {

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

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

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

@@ -2,6 +2,7 @@
 
 #include <Atomic/UI/UIEvents.h>
 #include <Atomic/UI/UIWidget.h>
+#include <Atomic/UI/UIButton.h>
 #include <Atomic/UI/UI.h>
 #include "JSVM.h"
 #include "JSUI.h"
@@ -16,6 +17,7 @@ JSUI::JSUI(Context* context) : Object(context)
     ctx_ = JSVM::GetJSVM(nullptr)->GetJSContext();
     SubscribeToEvent(E_WIDGETEVENT, HANDLER(JSUI, HandleWidgetEvent));
     SubscribeToEvent(E_WIDGETLOADED, HANDLER(JSUI, HandleWidgetLoaded));
+    SubscribeToEvent(E_POPUPMENUSELECT, HANDLER(JSUI, HandlePopupMenuSelect));
 }
 
 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)
 {
     using namespace WidgetEvent;

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

@@ -27,6 +27,7 @@ private:
 
     void HandleWidgetEvent(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);
 

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

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

@@ -12,6 +12,8 @@
 
 namespace tb {
 
+typedef void (*TBIDRegisterStringCallback) (uint32 id, const char* string);
+
 /** 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
 	set from a string which will be hashed into the uint32. */
@@ -43,6 +45,8 @@ public:
 	friend class TBLanguage;
 	TBStr debug_string;
 #endif
+
+    static TBIDRegisterStringCallback tbidRegisterCallback;
 };
 
 }; // namespace tb