Browse Source

Tab undocking and TB primitives

JimMarlowe 8 years ago
parent
commit
b7badf2cf4

+ 1 - 1
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", "UIPulldownMenu", "UIRadioButton", "UIScrollBar"],
+								"UIPromptWindow", "UIFinderWindow", "UIPulldownMenu", "UIRadioButton", "UIScrollBar", "UIDockWindow"],
 	"overloads" : {
 	},
 	"typescript_decl" : {

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

@@ -95,6 +95,7 @@ using namespace tb;
 #include "UIComponent.h"
 #include "UIRadioButton.h"
 #include "UIScrollBar.h"
+#include "UIDockWindow.h"
 
 #include "SystemUI/SystemUI.h"
 #include "SystemUI/SystemUIEvents.h"

+ 118 - 0
Source/Atomic/UI/UIDockWindow.cpp

@@ -0,0 +1,118 @@
+//
+// Copyright (c) 2014-2015, 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 <TurboBadger/tb_widgets.h>
+#include <TurboBadger/tb_widgets_common.h>
+#include <TurboBadger/tb_window.h>
+
+#include "../IO/Log.h"
+
+#include "UI.h"
+#include "UIEvents.h"
+#include "UIDockWindow.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+UIDockWindow::UIDockWindow(Context* context, bool createWidget, const String& title, UIWidget *contentptr, int minwidth, int minheight ) : UIWindow(context, false)
+{
+    if (createWidget)
+    {
+        tb:TBWidget *contents = contentptr->GetInternalWidget();
+        widget_ = new TBDockWindow( title.CString(), contents, minwidth, minheight );
+        widget_->SetDelegate(this);
+        GetSubsystem<UI>()->WrapWidget(this, widget_);
+    }
+}
+
+UIDockWindow::~UIDockWindow()
+{
+}
+
+void UIDockWindow::SetDockOrigin( String dockid ) // where using the dock button returns the content to
+{
+    if (!widget_)
+        return;
+
+   ((TBDockWindow*)widget_)->SetDockOrigin(TBIDC(dockid.CString()));
+
+}
+
+UIWidget *UIDockWindow::GetDockContent()  // the content that is being swapped around
+{
+    if (!widget_)
+        return NULL;
+
+    TBWidget* content = ((TBDockWindow*)widget_)->GetDockContent();
+
+    if (!content)
+        return 0;
+
+    UI* ui = GetSubsystem<UI>();
+
+    return ui->WrapWidget(content);
+
+}
+
+bool UIDockWindow::HasDockContent() // is there content in the dockwindow
+{
+    if (!widget_)
+        return false;
+
+    return ((TBDockWindow*)widget_)->HasDockContent();
+}
+
+void UIDockWindow::Dock( UIWidget *target ) // move the dock window content to somewhere else
+{
+    if (!widget_)
+        return;
+
+    if (!target)
+        return;
+
+    ((TBDockWindow*)widget_)->Dock( target->GetInternalWidget() );
+}
+
+void UIDockWindow::Show( UIWidget *host, int xpos, int ypos ) // show the dock window
+{
+    if (!widget_)
+        return;
+
+    if (!host)
+        return;
+
+    ((TBDockWindow*)widget_)->Show( host->GetInternalWidget(), xpos, ypos );
+
+}
+
+bool UIDockWindow::OnEvent(const tb::TBWidgetEvent &ev)
+{
+    return UIWidget::OnEvent(ev);
+}
+
+
+
+
+
+}

+ 56 - 0
Source/Atomic/UI/UIDockWindow.h

@@ -0,0 +1,56 @@
+//
+// Copyright (c) 2014-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<TurboBadger/tb_atomic_widgets.h>
+
+#include "UIWidget.h"
+#include "UIWindow.h"
+
+namespace Atomic
+{
+
+class ATOMIC_API UIDockWindow : public UIWindow
+{
+    ATOMIC_OBJECT(UIDockWindow, UIWindow)
+
+    public:
+
+    UIDockWindow(Context* context, bool createWidget = true, const String& title = String::EMPTY, UIWidget *contentptr = NULL, int minwidth = 800, int minheight=400 );
+    virtual ~UIDockWindow();
+
+    void SetDockOrigin( String dockid );  // where using the dock button returns the content to
+    UIWidget *GetDockContent();  // the content that is being swapped around
+    bool HasDockContent();  // is there content in the dockwindow
+    void Dock( UIWidget *target );  // move the dock window content to somewhere else
+    void Show( UIWidget *host, int xpos = 50, int ypos = 50 ); // show the dock window
+
+protected:
+
+    virtual bool OnEvent(const tb::TBWidgetEvent &ev);
+
+private:
+
+};
+
+}

+ 32 - 2
Source/Atomic/UI/UITabContainer.cpp

@@ -156,7 +156,7 @@ bool UITabContainer::DeletePage( int page )
 }
 
 /// adds a tab + page from layout file
-void UITabContainer::AddTabPageFile ( const String &tabname, const String &layoutFile )
+void UITabContainer::AddTabPageFile ( const String &tabname, const String &layoutFile, bool selecttab )
 {
     UIButton* button = new UIButton(context_);
     button->SetText(tabname);
@@ -176,10 +176,12 @@ void UITabContainer::AddTabPageFile ( const String &tabname, const String &layou
 
     Invalidate();
 
+    if (selecttab) 
+        SetCurrentPage( GetNumPages() -1 );
 }
 
 /// adds a tab + page widget(s)
-void UITabContainer::AddTabPageWidget ( const String &tabname, UIWidget *widget ) 
+void UITabContainer::AddTabPageWidget ( const String &tabname, UIWidget *widget, bool selecttab ) 
 {
     UIButton* button = new UIButton(context_);
     button->SetText(tabname);
@@ -199,7 +201,35 @@ void UITabContainer::AddTabPageWidget ( const String &tabname, UIWidget *widget
 
     Invalidate();
 
+    if (selecttab) 
+        SetCurrentPage( GetNumPages() -1 );
 }
 
+/// undocks the page into a window with the tab name, and removes the tab
+void UITabContainer::UndockPage ( int page )
+{
+    if (!widget_)
+        return;
+
+    ((TBTabContainer*)widget_)->UndockPage(page);
+
+    // tab container "feature", can not set it to the page number that was removed.
+    int num = 0;
+    if ( page - 1 > 0 ) num = page - 1;
+    SetCurrentPage(num);
+
+}
+
+/// docks content from a UIDockWindow with specified title
+bool UITabContainer::DockWindow ( String windowTitle )
+{
+    if (!widget_)
+        return false;
+    bool done = ((TBTabContainer*)widget_)->DockFromWindow(windowTitle.CString());
+    if (done) 
+        SetCurrentPage( GetNumPages() -1 );
+
+   return done;
+}
 
 }

+ 5 - 2
Source/Atomic/UI/UITabContainer.h

@@ -47,8 +47,11 @@ public:
     
     int GetCurrentPage(); /// returns the current page number
     bool DeletePage( int page ); /// deletes a tab + page, returns true if successful
-    void AddTabPageFile ( const String &tabname, const String &layoutFile ); /// adds a tab + page from file
-    void AddTabPageWidget ( const String &tabname, UIWidget *widget ); /// adds a tab + page widget(s)
+    void AddTabPageFile ( const String &tabname, const String &layoutFile, bool selecttab = true ); /// adds a tab + page from file
+    void AddTabPageWidget ( const String &tabname, UIWidget *widget, bool selecttab = true ); /// adds a tab + page widget(s)
+
+    void UndockPage ( int page ); /// undocks the page into a window with the tab name, and removes the tab
+    bool DockWindow ( String windowTitle ); /// docks content from a UIDockWindow with specified title
 
 protected:
 

+ 140 - 0
Source/ThirdParty/TurboBadger/tb_atomic_widgets.cpp

@@ -32,6 +32,7 @@
 #include "tb_editfield.h"
 #include "tb_menu_window.h"
 #include "tb_select.h"
+#include "tb_tab_container.h"
 
 #include <math.h>
 
@@ -759,5 +760,144 @@ void TBPulldownMenu::OnInflate(const INFLATE_INFO &info)
     TBWidget::OnInflate(info);
 }
 
+// == TBDockWindow ==========================================
+
+TBDockWindow::TBDockWindow( TBStr title, TBWidget *contentptr, int minwidth, int minheight ) : TBWindow()
+{
+    m_mover.AddChild(&m_redock_button);
+    m_redock_button.SetSkinBg(TBIDC("TBWindow.redock"));
+    m_redock_button.SetIsFocusable(false);
+    m_redock_button.SetID(TBIDC("TBWindow.redock"));
+    m_redock_button.SetVisibilility(WIDGET_VISIBILITY_INVISIBLE);
+
+    SetText(title);
+
+    TBStr uilayout; // undock host ui layout
+    uilayout.SetFormatted ( "TBLayout: axis: y, distribution: gravity\n\tlp: min-width: %ddp, min-height: %ddp\n\tTBLayout: id: \"undocklayout\", distribution: gravity\n", minwidth, minheight );
+    g_widgets_reader->LoadData(this, uilayout );
+    TBLayout *lo1 = GetWidgetByIDAndType<TBLayout>(TBID("undocklayout"));
+    lo1->AddChild(contentptr); // jam it into the window before the pointer gets stale
+    ResizeToFitContent();
+} 
+
+TBDockWindow::~TBDockWindow()
+{
+    if (m_resizer.GetParent()) RemoveChild(&m_resizer);
+    if (m_mover.GetParent()) RemoveChild(&m_mover);
+    if (m_close_button.GetParent()) m_mover.RemoveChild(&m_close_button);
+    if (m_redock_button.GetParent()) m_mover.RemoveChild(&m_redock_button);
+    m_mover.RemoveChild(&m_textfield);
+}
+
+void TBDockWindow::SetDockOrigin( TBID dockid )
+{
+     m_dockid = dockid;
+    if ( m_dockid > 0 ) //enable/show the (re)dock button is a return id is specified
+    {
+        m_redock_button.SetVisibilility(WIDGET_VISIBILITY_VISIBLE);
+    }
+}
+
+
+void TBDockWindow::Show( TBWidget *host, int xpos, int ypos )
+{
+    if ( host )
+    {
+        host->AddChild(this);
+        SetPosition( TBPoint( xpos, ypos) );
+    }
+}
+
+TBWidget *TBDockWindow::GetDockContent()
+{
+    TBLayout *lo1 = GetWidgetByIDAndType<TBLayout>(TBID("undocklayout"));
+    if ( lo1 )
+        return lo1->GetChildFromIndex(0);
+}
+
+bool TBDockWindow::HasDockContent()
+{
+    return ( GetDockContent() != NULL );
+}
+
+void TBDockWindow::Redock ()
+{
+    if ( m_dockid > 0 ) // see if there is a dock point id specified  
+    {
+        TBWidget *mytarget = GetParentRoot(true)->GetWidgetByID(m_dockid);
+        if (mytarget)
+            Dock (mytarget);
+    }
+}
+
+void TBDockWindow::Dock ( TBWidget *target )
+{
+    if ( !HasDockContent() ) return; 
+
+    if ( target ) // what kind of widget is it?
+    {
+        TBStr mystr;
+        TBWidget *mypage = NULL;
+        TBLayout *lo1 = NULL;
+        TBTabContainer *tc1 = NULL;
+        if ( tc1 = TBSafeCast<TBTabContainer>( target ) ) // handle TBTabContainer
+        {
+            mystr = GetText();
+            mypage = GetDockContent();
+            if (mypage)
+            {
+                TBButton *tbb = new TBButton();
+                tbb->SetID (TBID(mystr));
+                tbb->SetText(mystr);
+                mypage->GetParent()->RemoveChild(mypage);
+                tc1->GetContentRoot()->AddChild(mypage);
+                tc1->GetTabLayout()->AddChild(tbb);
+                tc1->Invalidate();
+                tc1->SetCurrentPage(tc1->GetNumPages()-1);
+                Close();
+            }
+        }
+    }   
+}
+
+bool TBDockWindow::OnEvent(const TBWidgetEvent &ev)
+{
+   if (ev.target == &m_close_button)
+    {
+        if (ev.type == EVENT_TYPE_CLICK)
+            Close();
+        return true;
+    }
+   if (ev.target == &m_redock_button)
+    {
+        if (ev.type == EVENT_TYPE_CLICK)
+            Redock();
+        return true;
+    }
+    return TBWidget::OnEvent(ev);
+}
+
+void TBDockWindow::OnResized(int old_w, int old_h)
+{
+    // Apply gravity on children
+    TBWidget::OnResized(old_w, old_h);
+    // Manually move our own decoration children
+    // FIX: Put a layout in the TBMover so we can add things there nicely.
+    int title_height = GetTitleHeight();
+    m_mover.SetRect(TBRect(0, 0, GetRect().w, title_height));
+    PreferredSize ps = m_resizer.GetPreferredSize();
+    m_resizer.SetRect(TBRect(GetRect().w - ps.pref_w, GetRect().h - ps.pref_h, ps.pref_w, ps.pref_h));
+    TBRect mover_rect = m_mover.GetPaddingRect();
+    int button_size = mover_rect.h;
+    m_close_button.SetRect(TBRect(mover_rect.x + mover_rect.w - button_size, mover_rect.y, button_size, button_size));
+    if (m_settings & WINDOW_SETTINGS_CLOSE_BUTTON)
+        mover_rect.w -= button_size;
+    // add redock button to header
+    m_redock_button.SetRect(TBRect(mover_rect.x + mover_rect.w - button_size, mover_rect.y, button_size, button_size));
+    if (m_settings & WINDOW_SETTINGS_CLOSE_BUTTON)
+        mover_rect.w -= button_size;
+    m_textfield.SetRect(mover_rect);
+}
+
 
 }; // namespace tb

+ 28 - 0
Source/ThirdParty/TurboBadger/tb_atomic_widgets.h

@@ -264,6 +264,34 @@ protected:
 };
 
 
+/** TBDockWindow is a window for undocking (and redocking) content */
+
+class TBDockWindow : public TBWindow
+{
+public:
+    // For safe typecasting
+    TBOBJECT_SUBCLASS(TBDockWindow, TBWindow);
+
+    TBDockWindow( TBStr title, TBWidget *contentptr, int minwidth = 800, int minheight = 400 );
+    virtual ~TBDockWindow();
+
+    void SetDockOrigin( TBID dockid );
+    TBWidget *GetDockContent();
+    bool HasDockContent();
+    void Dock( TBWidget *target );
+    void Show(TBWidget *host, int xpos = 50, int ypos = 50 );
+
+    virtual bool OnEvent(const TBWidgetEvent &ev);
+    virtual void OnResized(int old_w, int old_h);
+
+protected:
+
+    void Redock();
+
+    TBWidget m_redock_button;  // return content to origin
+    TBID m_dockid; /// the TBID of the origin container
+
+};
 
 
 }; // namespace tb

+ 49 - 0
Source/ThirdParty/TurboBadger/tb_tab_container.cpp

@@ -6,6 +6,12 @@
 #include "tb_tab_container.h"
 #include <assert.h>
 
+// ATOMIC BEGIN
+#include "tb_node_tree.h"
+#include "tb_widgets_reader.h"
+#include "tb_atomic_widgets.h"
+// ATOMIC END
+
 namespace tb {
 
 // == TBTabLayout =======================================================================
@@ -182,4 +188,47 @@ void TBTabContainer::OnProcess()
     }
 }
 
+// ATOMIC BEGIN
+
+/// takes the contents of a DockWindow into a tab in a tabcontainer 
+bool TBTabContainer::DockFromWindow ( TBStr windowTitle )
+{
+    int nn = 0;
+    TBLinkListOf<TBWidget>::Iterator mx = GetParentRoot(true)->GetIteratorForward();
+    while (TBWidget *mxw = mx.GetAndStep())
+    {
+        if ( mxw->GetText().Equals(windowTitle) )
+        {
+            TBDockWindow *dw1 = TBSafeCast<TBDockWindow>( mxw );
+            if (dw1) 
+                dw1->Dock ( this );
+            return true;
+        }
+        nn++;
+    }
+    return false;
+}
+
+/// undocks the page into a window with the tab name, and removes the tab
+void TBTabContainer::UndockPage ( int page )
+{
+    TBWidget *mytab = GetTabLayout()->GetChildFromIndex(page);  // find the offending tab 
+    TBWidget *mypage = GetContentRoot()->GetChildFromIndex(page);   // find the offending page (layout)
+
+    if (mytab == NULL || mypage == NULL ) return; // nobody home
+
+    TBStr tabstr = mytab->GetText(); //get the name/text of the tab
+    GetTabLayout()->RemoveChild(mytab); // remove, delete the tab[page] button
+    mytab->Die();  // and get rid of it
+    GetContentRoot()->RemoveChild(mypage);  // remove the pagewidget[page] from the content root (without deleting it, hopefully)
+    TBDockWindow *mywindow = new TBDockWindow(tabstr, mypage); // create an undock window.
+    mywindow->SetDockOrigin( GetID() );  //tell it to redock here
+    mywindow->Show(GetParentRoot(true)); 
+
+    Invalidate(); // and tell everyone the party is over.
+
+}
+
+// ATOMIC END
+
 }; // namespace tb

+ 6 - 0
Source/ThirdParty/TurboBadger/tb_tab_container.h

@@ -71,6 +71,12 @@ public:
 
     virtual TBWidget *GetContentRoot() { return &m_content_root; }
     TBLayout *GetTabLayout() { return &m_tab_layout; }
+    
+// ATOMIC BEGIN
+    virtual void UndockPage ( int page ); /// undocks the page into a window with the tab name, and removes the tab
+    virtual bool DockFromWindow ( TBStr windowTitle ); /// takes the contents of a DockWindow into a tab in a tabcontainer 
+// ATOMIC END
+
 protected:
     TBLayout m_root_layout;
     TBTabLayout m_tab_layout;

+ 43 - 0
Source/ThirdParty/TurboBadger/tb_widgets.cpp

@@ -17,6 +17,8 @@
 #include "tb_editfield.h"
 #endif // TB_ALWAYS_SHOW_EDIT_FOCUS
 
+#include <stdio.h>  // for printfs in PrintPretty
+
 namespace tb {
 
 //static data
@@ -773,6 +775,47 @@ TBWidget *TBWidget::GetWidgetAt(int x, int y, bool include_children) const
     return last_match;
 }
 
+// ATOMIC BEGIN
+
+/** Returns the number of children this widget contains. */
+int TBWidget::numChildren()
+{
+    int nn = 0;
+    TBLinkListOf<TBWidget>::Iterator mx = GetIteratorForward();
+    while (TBWidget *mxw = mx.GetAndStep())
+    {
+        nn++;
+    }
+    return nn;
+}
+
+/** print out the widget tree */
+void TBWidget::PrintPretty( TBStr indent, bool last)
+{
+    printf("%s", indent.CStr());
+    if (last)
+    {
+       printf("\\-");
+       indent.Append("  ");
+    }
+    else
+    {
+       printf("|-");
+       indent.Append("| ");
+    }
+    TBStr shorty(GetText(), 32); 
+    printf("%s:%u `%s`\n", GetClassName(), (uint32)GetID(), shorty.CStr() );
+    int num = numChildren();
+    for (int ii = 0; ii < num; ii++)
+    {
+        TBWidget *child = GetChildFromIndex(ii);
+        child->PrintPretty(indent, ii == num - 1);
+    }
+}
+
+// ATOMIC END
+
+
 TBWidget *TBWidget::GetChildFromIndex(int index) const
 {
     int i = 0;

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

@@ -619,6 +619,16 @@ public:
     TBLinkListOf<TBWidget>::Iterator GetIteratorForward() { return m_children.IterateForward(); }
     TBLinkListOf<TBWidget>::Iterator GetIteratorBackward() { return m_children.IterateBackward(); }
 
+// ATOMIC BEGIN
+
+    /** Returns the number of children this widget contains. */
+    int numChildren();
+
+    /** print out the widget tree to stdout */
+    void PrintPretty( TBStr indent, bool last);
+
+// ATOMIC END
+
     /** Return true if this widget is the same or a ancestor of other_widget. */
     bool IsAncestorOf(TBWidget *other_widget) const;