From 5c9b3865acb01f6dacfab7fe6b9d40a70e93fca8 Mon Sep 17 00:00:00 2001 From: JimMarlowe Date: Sun, 18 Jun 2017 08:13:02 -0700 Subject: [PATCH 1/3] add UIPulldownMenu widget --- Script/Packages/Atomic/UI.json | 6 +- Source/Atomic/UI/UI.cpp | 9 ++ Source/Atomic/UI/UIPulldownMenu.cpp | 84 ++++++++++++ Source/Atomic/UI/UIPulldownMenu.h | 51 ++++++++ .../TurboBadger/tb_atomic_widgets.cpp | 123 +++++++++++++++++- .../TurboBadger/tb_atomic_widgets.h | 62 ++++++++- 6 files changed, 331 insertions(+), 4 deletions(-) create mode 100644 Source/Atomic/UI/UIPulldownMenu.cpp create mode 100644 Source/Atomic/UI/UIPulldownMenu.h diff --git a/Script/Packages/Atomic/UI.json b/Script/Packages/Atomic/UI.json index 14c6ecd54a..6a0f9a77c3 100755 --- a/Script/Packages/Atomic/UI.json +++ b/Script/Packages/Atomic/UI.json @@ -10,7 +10,7 @@ "UISkinImage", "UITabContainer", "UISceneView", "UIPreferredSize", "UIDragObject", "UIContainer", "UISection", "UIInlineSelect", "UITextureWidget", "UIColorWidget", "UIColorWheel", "UIScrollContainer", "UISeparator", "UIDimmer", "UISelectDropdown", "UISlider", "UIBargraph", - "UIPromptWindow", "UIFinderWindow"], + "UIPromptWindow", "UIFinderWindow", "UIPulldownMenu"], "overloads" : { }, "typescript_decl" : { @@ -22,7 +22,9 @@ "getWidgetAt(x: number, y: number, include_children: boolean): T;" ], "UIWidget": [ - "getWidget(id: string): T;" + "getWidget(id: string): T;", + "onEvent: () => void;", + "onChanged: () => void;" ] } diff --git a/Source/Atomic/UI/UI.cpp b/Source/Atomic/UI/UI.cpp index a427b9f3c1..86f8afb62f 100644 --- a/Source/Atomic/UI/UI.cpp +++ b/Source/Atomic/UI/UI.cpp @@ -90,6 +90,7 @@ using namespace tb; #include "UIBargraph.h" #include "UIPromptWindow.h" #include "UIFinderWindow.h" +#include "UIPulldownMenu.h" #include "SystemUI/SystemUI.h" #include "SystemUI/SystemUIEvents.h" @@ -741,6 +742,14 @@ UIWidget* UI::WrapWidget(tb::TBWidget* widget) return select; } + if (widget->IsOfType()) + { + UIPulldownMenu* select = new UIPulldownMenu(context_, false); + select->SetWidget(widget); + WrapWidget(select, widget); + return select; + } + if (widget->IsOfType()) { // don't wrap the close button of a TBWindow.close diff --git a/Source/Atomic/UI/UIPulldownMenu.cpp b/Source/Atomic/UI/UIPulldownMenu.cpp new file mode 100644 index 0000000000..43ad40a5b6 --- /dev/null +++ b/Source/Atomic/UI/UIPulldownMenu.cpp @@ -0,0 +1,84 @@ +// +// Copyright (c) 2017, THUNDERBEAST GAMES LLC All rights reserved +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#include +#include +#include + +#include + +#include "UI.h" +#include "UIEvents.h" +#include "UIPulldownMenu.h" + +using namespace tb; + +namespace Atomic +{ + +UIPulldownMenu::UIPulldownMenu(Context* context, bool createWidget) : UIButton(context, false) +{ + if (createWidget) + { + widget_ = new TBPulldownMenu(); + widget_->SetDelegate(this); + GetSubsystem()->WrapWidget(this, widget_); + } +} + +UIPulldownMenu::~UIPulldownMenu() +{ + +} + +void UIPulldownMenu::SetSource(UISelectItemSource* source) +{ + if (!widget_) + return; + + ((TBSelectDropdown*)widget_)->SetSource(source ? source->GetTBItemSource() : NULL); + +} + +const String& UIPulldownMenu::GetSelectedId() +{ + if (!widget_) + { + if (sid_.Length()) + sid_.Clear(); + return sid_; + } + + UI* ui = GetSubsystem(); + ui->GetTBIDString(((TBPulldownMenu*)widget_)->GetValueID(), sid_); + + return sid_; + +} +bool UIPulldownMenu::OnEvent(const tb::TBWidgetEvent &ev) +{ + + return UIButton::OnEvent(ev); + +} + +} diff --git a/Source/Atomic/UI/UIPulldownMenu.h b/Source/Atomic/UI/UIPulldownMenu.h new file mode 100644 index 0000000000..d252b26e8f --- /dev/null +++ b/Source/Atomic/UI/UIPulldownMenu.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2017, THUNDERBEAST GAMES LLC All rights reserved +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +#pragma once + +#include "UISelectItem.h" +#include "UIButton.h" + +namespace Atomic +{ + +class ATOMIC_API UIPulldownMenu : public UIButton +{ + ATOMIC_OBJECT(UIPulldownMenu, UIButton) + +public: + + UIPulldownMenu(Context* context, bool createWidget = true); + virtual ~UIPulldownMenu(); + + void SetSource(UISelectItemSource* source); /// for programming the pulled down menu + + const String& GetSelectedId(); /// return id of entry selected in menu + +protected: + + virtual bool OnEvent(const tb::TBWidgetEvent &ev); + String sid_; /// cached selected item tbid + +}; + +} diff --git a/Source/ThirdParty/TurboBadger/tb_atomic_widgets.cpp b/Source/ThirdParty/TurboBadger/tb_atomic_widgets.cpp index 54bdacbe4c..fac60f70fe 100755 --- a/Source/ThirdParty/TurboBadger/tb_atomic_widgets.cpp +++ b/Source/ThirdParty/TurboBadger/tb_atomic_widgets.cpp @@ -3,7 +3,7 @@ // == See tb_core.h for more information. == // ================================================================================ // -// Copyright (c) 2016, THUNDERBEAST GAMES LLC All rights reserved +// Copyright (c) 2016-2017, THUNDERBEAST GAMES LLC All rights reserved // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,6 +31,8 @@ #include "tb_atomic_widgets.h" #include "tb_editfield.h" #include "tb_menu_window.h" +#include "tb_select.h" + #include namespace tb { @@ -638,5 +640,124 @@ TBWidget *TBFinderWindow::FindParentList( TBWidget *widget) // utility for deali return NULL; } +// == TBPulldownMenu ========================================== + +TBPulldownMenu::TBPulldownMenu() + : m_value(-1) +{ + SetSource(&m_default_source); + SetSkinBg(TBIDC("TBSelectDropdown"), WIDGET_INVOKE_INFO_NO_CALLBACKS); +} + +TBPulldownMenu::~TBPulldownMenu() +{ + SetSource(nullptr); + CloseWindow(); +} + +void TBPulldownMenu::OnSourceChanged() +{ + m_value = -1; + m_valueid = TBID(); + if (m_source && m_source->GetNumItems()) + SetValue(0); +} + +void TBPulldownMenu::SetValue(int value) +{ + if (!m_source) + return; + m_value = value; + m_valueid = GetSelectedItemID(); + InvokeModifiedEvent( m_valueid ); +} + +TBID TBPulldownMenu::GetSelectedItemID() +{ + if (m_source && m_value >= 0 && m_value < m_source->GetNumItems()) + return m_source->GetItemID(m_value); + return TBID(); +} + +void TBPulldownMenu::InvokeModifiedEvent( TBID entryid ) +{ + TBWidgetEvent ev( EVENT_TYPE_CHANGED); + // TBIDC does not register the TBID with the UI system, so do it this way + ev.target = this; // who am I + ev.ref_id = entryid; // id of whom we clicked + TBWidget::OnEvent(ev); // forward to delegate +} + +void TBPulldownMenu::OpenWindow() +{ + if (!m_source || !m_source->GetNumItems() || m_window_pointer.Get()) + return; + + if (TBMenuWindow *window = new TBMenuWindow(this, TBIDC("TBPulldownMenu.menu"))) + { + m_window_pointer.Set(window); + window->SetSkinBg(TBIDC("TBSelectDropdown.window")); + window->Show(m_source, TBPopupAlignment()); + } +} + +void TBPulldownMenu::CloseWindow() +{ + if (TBMenuWindow *window = GetMenuIfOpen()) + window->Close(); +} + +TBMenuWindow *TBPulldownMenu::GetMenuIfOpen() const +{ + return TBSafeCast(m_window_pointer.Get()); +} + +bool TBPulldownMenu::OnEvent(const TBWidgetEvent &ev) +{ + if ( ev.target->IsOfType() && ev.type == EVENT_TYPE_CLICK) + { + // Open the menu, or set the value and close it if already open (this will + // happen when clicking by keyboard since that will call click on this button) + if (TBMenuWindow *menu_window = GetMenuIfOpen()) + { + TBWidgetSafePointer tmp(this); + int value = menu_window->GetList()->GetValue(); + menu_window->Die(); + if (tmp.Get()) + SetValue(value); + } + else + OpenWindow(); + return true; + } + else if (ev.target->GetID() == TBIDC("TBPulldownMenu.menu") && ev.type == EVENT_TYPE_CLICK ) + { + if (TBMenuWindow *menu_window = GetMenuIfOpen()) + SetValue(menu_window->GetList()->GetValue()); + return true; + } + else if (ev.target == this && m_source && ev.IsKeyEvent()) + { + if (TBMenuWindow *menu_window = GetMenuIfOpen()) + { + // Redirect the key strokes to the list + TBWidgetEvent redirected_ev(ev); + return menu_window->GetList()->InvokeEvent(redirected_ev); + } + } + return false; +} + +TB_WIDGET_FACTORY( TBPulldownMenu, TBValue::TYPE_INT, WIDGET_Z_TOP) {} + +extern void ReadItems(TBNode *node, TBGenericStringItemSource *target_source); // blind function that lives in tb_widgets_reader.cpp + +void TBPulldownMenu::OnInflate(const INFLATE_INFO &info) +{ + // Read items (if there is any) into the default source + ReadItems(info.node, GetDefaultSource()); + TBWidget::OnInflate(info); +} + }; // namespace tb diff --git a/Source/ThirdParty/TurboBadger/tb_atomic_widgets.h b/Source/ThirdParty/TurboBadger/tb_atomic_widgets.h index 5ce0fc4c4b..0207cd4a48 100755 --- a/Source/ThirdParty/TurboBadger/tb_atomic_widgets.h +++ b/Source/ThirdParty/TurboBadger/tb_atomic_widgets.h @@ -3,7 +3,7 @@ // == See tb_core.h for more information. == // ================================================================================ // -// Copyright (c) 2016, THUNDERBEAST GAMES LLC All rights reserved +// Copyright (c) 2016-2017, THUNDERBEAST GAMES LLC All rights reserved // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -32,6 +32,9 @@ #include "tb_widgets_listener.h" #include "tb_widgets_common.h" #include "tb_window.h" +#include "tb_scroll_container.h" +#include "tb_select_item.h" +#include "tb_menu_window.h" #define UIPROMPTMESSAGEID 1 #define UIPROMPTEDITID 2 @@ -202,6 +205,63 @@ class TBFinderWindow : public TBWindow, private TBWidgetListener }; +/** TBSelectDropdown shows a button that opens a popup with a TBSelectList with items + provided by a TBSelectItemSource. */ + +class TBPulldownMenu : public TBButton, public TBSelectItemViewer +{ +public: + // For safe typecasting + TBOBJECT_SUBCLASS(TBPulldownMenu, TBButton); + + TBPulldownMenu(); + ~TBPulldownMenu(); + + /** Get the default item source for this widget. This source can be used to add + items of type TBGenericStringItem to this widget. */ + TBGenericStringItemSource *GetDefaultSource() { return &m_default_source; } + + /** Save the selected item. Transfers value from menu to button parent */ + virtual void SetValue(int value); + virtual int GetValue() { return m_value; } + + /** Save the selected item TBID. Transfers value from menu to button parent */ + void SetValueID(TBID value) { m_valueid = value; } + TBID GetValueID() { return m_valueid; } + + /** Get the ID of the selected item, or 0 if there is no item selected. */ + TBID GetSelectedItemID(); + + /** Open the window if the model has items. */ + void OpenWindow(); + + /** Close the window if it is open. */ + void CloseWindow(); + + /** Return the menu window if it's open, or nullptr. */ + TBMenuWindow *GetMenuIfOpen() const; + + virtual void OnInflate(const INFLATE_INFO &info); + virtual bool OnEvent(const TBWidgetEvent &ev); + + // TBSelectItemViewer + virtual void OnSourceChanged(); + virtual void OnItemChanged(int index) {} + virtual void OnItemAdded(int index) {} + virtual void OnItemRemoved(int index) {} + virtual void OnAllItemsRemoved() {} + + virtual bool OnWidgetInvokeEvent(TBWidget *widget, const TBWidgetEvent &ev) { return false; } + +protected: + + void InvokeModifiedEvent(TBID entryid); + + TBGenericStringItemSource m_default_source; + TBWidgetSafePointer m_window_pointer; ///< Points to the dropdown window if opened + int m_value; /// which list item has been selected + TBID m_valueid; /// the TBID of the list item that was selected +}; From e9ecf9a39a4460e5605832cd1918db52c3273209 Mon Sep 17 00:00:00 2001 From: JimMarlowe Date: Mon, 19 Jun 2017 08:31:06 -0700 Subject: [PATCH 2/3] add event to onEvent function --- Script/Packages/Atomic/UI.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Script/Packages/Atomic/UI.json b/Script/Packages/Atomic/UI.json index 6a0f9a77c3..ac40f60680 100755 --- a/Script/Packages/Atomic/UI.json +++ b/Script/Packages/Atomic/UI.json @@ -23,7 +23,7 @@ ], "UIWidget": [ "getWidget(id: string): T;", - "onEvent: () => void;", + "onEvent: (data:any) => void;", "onChanged: () => void;" ] } From 9770ec1f53d210b18dba817e7f39b7d8b5a1546f Mon Sep 17 00:00:00 2001 From: JimMarlowe Date: Mon, 19 Jun 2017 15:58:25 -0700 Subject: [PATCH 3/3] made the onEvent better --- Script/Packages/Atomic/UI.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Script/Packages/Atomic/UI.json b/Script/Packages/Atomic/UI.json index ac40f60680..f1d340d1a9 100755 --- a/Script/Packages/Atomic/UI.json +++ b/Script/Packages/Atomic/UI.json @@ -23,7 +23,7 @@ ], "UIWidget": [ "getWidget(id: string): T;", - "onEvent: (data:any) => void;", + "onEvent: (eventData:UIWidgetEvent) => void;", "onChanged: () => void;" ] }