Browse Source

Merge pull request #1617 from JimMarlowe/JM-MENU-MATRIX

Add Atomic UIButtonGrid widget
JoshEngebretson 8 years ago
parent
commit
9427db1f6d

+ 2 - 1
Script/Packages/Atomic/UI.json

@@ -10,7 +10,8 @@
 								"UISkinImage", "UITabContainer", "UISceneView", "UIPreferredSize", "UIDragObject",
 								"UISkinImage", "UITabContainer", "UISceneView", "UIPreferredSize", "UIDragObject",
 								"UIContainer", "UISection", "UIInlineSelect", "UITextureWidget", "UIColorWidget", "UIColorWheel",
 								"UIContainer", "UISection", "UIInlineSelect", "UITextureWidget", "UIColorWidget", "UIColorWheel",
 								"UIScrollContainer", "UISeparator", "UIDimmer", "UISelectDropdown", "UISlider", "UIBargraph",
 								"UIScrollContainer", "UISeparator", "UIDimmer", "UISelectDropdown", "UISlider", "UIBargraph",
-								"UIPromptWindow", "UIFinderWindow", "UIPulldownMenu", "UIRadioButton", "UIScrollBar", "UIDockWindow"],
+								"UIPromptWindow", "UIFinderWindow", "UIPulldownMenu", "UIRadioButton", "UIScrollBar", "UIDockWindow",
+								"UIButtonGrid"],
 	"overloads" : {
 	"overloads" : {
 	},
 	},
 	"typescript_decl" : {
 	"typescript_decl" : {

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

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

+ 286 - 0
Source/Atomic/UI/UIButtonGrid.cpp

@@ -0,0 +1,286 @@
+//
+// 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.
+//
+
+#include <TurboBadger/tb_widgets.h>
+#include <TurboBadger/tb_widgets_common.h>
+#include <TurboBadger/tb_layout.h>
+
+#include "UI.h"
+#include "UIEvents.h"
+#include "UIWidget.h"
+#include "UILayout.h"
+#include "UIButtonGrid.h"
+
+using namespace tb;
+
+namespace Atomic
+{
+
+UIButtonGrid::UIButtonGrid(Context* context, int numRows, int numCols, int margin, bool createWidget ) 
+    : UIWidget(context, false),
+    rows_(numRows),
+    columns_(numCols),
+    margin_(margin),
+    rowHeight_(0),
+    columnWidth_(0),
+    addCount_(0)
+{
+    if (createWidget)
+    {
+        widget_ = new TBLayout(AXIS_Y); // build upon a stock TBLayout
+        widget_->SetDelegate(this);
+        widget_->SetGravity(WIDGET_GRAVITY_ALL);
+        GetSubsystem<UI>()->WrapWidget(this, widget_);
+        GenerateGrid();
+    }
+}
+
+UIButtonGrid::~UIButtonGrid()
+{
+}
+
+void UIButtonGrid::SetGridText (int row, int column, String str)
+{
+    if (!widget_)
+        return;
+       
+    TBLayout *lo0 = (TBLayout *)widget_->GetChildFromIndex(row);  // find row
+    if (lo0) 
+    {
+        TBButton *b0 = (TBButton *)lo0->GetChildFromIndex(column);  // find column
+        if (b0)
+        {
+           b0->SetText( str.CString() );
+        } 
+    }
+}
+
+/// add strings starting at 0,0 and filling out columns, then next row, returns count
+int UIButtonGrid::AddGridText ( String str )
+{
+    int row = 0;
+    int column = 0;
+    if ( addCount_ > ( rows_ * columns_) ) return addCount_; // dont write past the end of the grid
+    row = addCount_ / columns_;
+    column = addCount_ % columns_;
+    SetGridText ( row, column, str );
+    addCount_++;
+    return addCount_-1;
+}
+
+/// returns number of rows that were programmed
+int UIButtonGrid::GetNumRows() const
+{
+    return rows_;
+}
+
+/// returns number of columns that were programmed
+int UIButtonGrid::GetNumColumns() const
+{
+    return columns_;
+}
+
+/// returns current row height
+int UIButtonGrid::GetRowHeight() const
+{
+    return rowHeight_;
+}
+
+/// returns current column width
+int UIButtonGrid::GetColumnWidth() const
+{
+    return columnWidth_;
+}
+
+/// returns current margin value
+int UIButtonGrid::GetMargin() const
+{
+    return margin_;
+}
+
+String UIButtonGrid::GetGridId( int row, int column ) 
+{
+    return String( 'A' + row ) + String(column); // generate spreadsheet style id
+}
+
+String UIButtonGrid::GetGridText(int row, int column)
+{
+    if (!widget_)
+        return "";
+    
+    TBLayout *lo0 = (TBLayout *)widget_->GetChildFromIndex(row);  // find row
+    if (lo0) 
+    {
+        TBButton *b0 = (TBButton *)lo0->GetChildFromIndex(column);  // find column
+        if (b0)
+        {
+            TBStr foo;
+            if ( b0->GetText( foo ) )
+                return foo.CStr();
+        } 
+    }
+    return "";
+}
+
+/// returns text at count
+String UIButtonGrid::AtGridText( int count )
+{
+    int row = 0;
+    int column = 0;
+    row = count / columns_;
+    column = count % columns_;
+    return GetGridText( row, column );
+}
+
+UIWidget* UIButtonGrid::GetGridWidget(int row, int column)
+{
+    if (!widget_)
+        return NULL;
+
+    TBWidget *mywidget = NULL;
+    TBLayout *lo0 = (TBLayout *)widget_->GetChildFromIndex(row); // find row
+    if (lo0) 
+    {
+        mywidget = lo0->GetChildFromIndex(column);  // find column
+    }
+    if ( mywidget )
+    {
+        UI* ui = GetSubsystem<UI>();
+        return ui->WrapWidget(mywidget);
+    }
+   return NULL; 
+}
+
+/// returns widget at count
+UIWidget* UIButtonGrid::AtGridWidget( int count )
+{
+    int row = 0;
+    int column = 0;
+    row = count / columns_;
+    column = count % columns_;
+    return GetGridWidget ( row, column );
+}
+
+void UIButtonGrid::GenerateGrid()
+{
+    if ( widget_ && widget_->numChildren() == 0 )  // build once.
+    {
+        ((TBLayout *)widget_)->SetSpacing(margin_);
+        for (int nn=0; nn<rows_; nn++ )
+            AddGridRow( nn );
+    }
+}
+
+void UIButtonGrid::AddGridRow( int rownum )
+{
+    TBLayout *lo0 = new TBLayout(); // make a new layout
+    lo0->SetID( TBID (rownum) );
+    lo0->SetLayoutConfig ( "XACAC" ); // do config + (spacing) margin
+    lo0->SetSpacing(margin_);
+    int cc = 0;
+    for ( cc=0; cc<columns_; cc++) // stuff new button ( with preferred size, new id ) in.
+    {
+        LayoutParams *lp0 = new LayoutParams();
+        lp0->SetWidth( columnWidth_ <= 0 ? 1 : columnWidth_);
+        lp0->SetHeight( rowHeight_ <= 0 ? 1 : rowHeight_);
+        TBButton *b0 = new TBButton();
+        b0->SetLayoutParams(*lp0);
+        b0->SetSqueezable(true);
+        TBStr myid;
+        myid.SetFormatted ( "%c%d", 'A' + rownum, cc+1 );
+        b0->SetID( TBID (myid) );
+        lo0->AddChild ( b0 );
+    }
+    widget_->AddChild ( lo0 );
+}
+
+/// will disable buttons that havent set any text, and enable those with text.
+void UIButtonGrid::DisableEmptyButtons()
+{
+    int row = 0;
+    int column = 0;
+    for ( row=0; row<rows_; row++ )
+    {
+        TBLayout *lo0 = (TBLayout *)widget_->GetChildFromIndex(row);  // find row layout
+        if (lo0) 
+        {
+            for ( column=0; column<columns_; column++ )
+            {
+                TBButton *b0 = (TBButton *)lo0->GetChildFromIndex(column);  // find column button
+                if (b0)
+                {
+                    TBStr foo;
+                    if ( b0->GetText( foo ) )
+                    {
+                        b0->SetState(WIDGET_STATE_DISABLED, foo.IsEmpty() );
+                    }
+                }
+            }
+        }
+    }  
+}
+
+
+void UIButtonGrid::ResizeGrid()
+{
+    if ( rows_ == 0 || columns_ == 0 ) return; // dont do bad maths.
+
+    TBRect myrect = widget_->GetRect();
+    rowHeight_ = (int)(  (myrect.h - (margin_ * rows_ )) / rows_ );
+    columnWidth_ = (int)( (myrect.w -( margin_ * columns_ )) / columns_ );
+
+    if ( rowHeight_ <= 1) rowHeight_ = 1;
+    if ( columnWidth_ <= 1)  columnWidth_ = 1;
+
+    int row = 0;
+    int column = 0;
+    for ( row=0; row<rows_; row++ )
+    {
+        TBLayout *lo0 = (TBLayout *)widget_->GetChildFromIndex(row);  // find row layout
+        if (lo0) 
+        {
+            for ( column=0; column<columns_; column++ )
+            {
+                TBButton *b0 = (TBButton *)lo0->GetChildFromIndex(column);  // find column button
+                if (b0)
+                {
+                    LayoutParams *lp1 = new LayoutParams(); // replace with new calced values
+                    lp1->SetWidth(columnWidth_);
+                    lp1->SetHeight(rowHeight_);
+                    b0->SetLayoutParams(*lp1);
+                }
+            }
+        }
+    }
+}
+
+void UIButtonGrid::OnResized(int old_w, int old_h) 
+{
+    ResizeGrid();
+}
+
+bool UIButtonGrid::OnEvent(const tb::TBWidgetEvent &ev)
+{
+    return UIWidget::OnEvent(ev);
+}
+
+}

+ 93 - 0
Source/Atomic/UI/UIButtonGrid.h

@@ -0,0 +1,93 @@
+//
+// 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 <ThirdParty/TurboBadger/tb_layout.h>
+
+#include "UIWidget.h"
+
+namespace Atomic
+{
+ 
+/// A grid of buttons that keep their shape and size, with minimal programming.
+class ATOMIC_API UIButtonGrid : public UIWidget
+{
+    ATOMIC_OBJECT(UIButtonGrid, UIWidget)
+
+public:
+
+    UIButtonGrid(Context* context, int numRows, int numColumns, int margin=0, bool createWidget = true );
+    virtual ~UIButtonGrid();
+    
+    /// returns id text for a row,column location, ie, A1 for location 0,0
+    String GetGridId( int row, int column );
+    /// set the button text at the row,column location
+    void SetGridText ( int row, int column, String str );
+    /// returns the button text at the row,column location
+    String GetGridText( int row, int column );
+    /// returns widget at the row,column location
+    UIWidget* GetGridWidget( int row, int column );
+    /// adds button text strings starting at 0,0 and filling out by cols, then rows, returns count
+    int AddGridText ( String str );
+    /// resets the counter for AddGridText()
+    void ResetAddCount() { addCount_ = 0; }
+    /// returns the widget at count
+    UIWidget* AtGridWidget( int count );
+    /// returns the button text at count
+    String AtGridText( int count );
+    /// convience function to disable buttons with no text, and enable those with text.
+    void DisableEmptyButtons();
+    /// returns number of rows that were programmed
+    int GetNumRows() const;
+    /// returns number of columns that were programmed
+    int GetNumColumns() const;
+    /// returns current row height value
+    int GetRowHeight() const;
+    /// returns current column width value
+    int GetColumnWidth() const;
+    /// returns current margin value
+    int GetMargin() const;
+
+protected:
+
+   virtual bool OnEvent(const tb::TBWidgetEvent &ev);
+   virtual void OnResized(int old_w, int old_h);
+
+private:
+    /// internal method to create the widgets in the assembly
+    void GenerateGrid();
+    /// internal method to adjust the row and column sizes based on new geometry
+    void ResizeGrid();
+    /// internal utility method to create a row of widgets.
+    virtual void AddGridRow( int rownum );
+
+    int rows_;
+    int columns_;
+    int margin_;
+    int rowHeight_;
+    int columnWidth_;
+    int addCount_;
+
+};
+
+}

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

@@ -1066,6 +1066,12 @@ UIView* UIWidget::GetView()
     return 0;
     return 0;
 }
 }
 
 
+
+void UIWidget::OnResized(int old_w, int old_h)
+{
+    // default implementation does nothing
+}
+
 void UIWidget::OnFocusChanged(bool focused)
 void UIWidget::OnFocusChanged(bool focused)
 {
 {
     using namespace WidgetFocusChanged;
     using namespace WidgetFocusChanged;

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

@@ -351,6 +351,7 @@ protected:
 
 
     virtual bool OnEvent(const tb::TBWidgetEvent &ev);
     virtual bool OnEvent(const tb::TBWidgetEvent &ev);
     virtual void OnDelete();
     virtual void OnDelete();
+    virtual void OnResized(int old_w, int old_h);
 
 
     String id_;
     String id_;
     tb::TBWidget* widget_;
     tb::TBWidget* widget_;

+ 5 - 0
Source/ThirdParty/TurboBadger/tb_layout.cpp

@@ -482,6 +482,11 @@ void TBLayout::OnResized(int old_w, int old_h)
     InvalidateLayout(INVALIDATE_LAYOUT_TARGET_ONLY);
     InvalidateLayout(INVALIDATE_LAYOUT_TARGET_ONLY);
     SizeConstraints sc(GetRect().w, GetRect().h);
     SizeConstraints sc(GetRect().w, GetRect().h);
     ValidateLayout(sc);
     ValidateLayout(sc);
+
+    // ATOMIC BEGIN  So pure UIWidgets can handle resize
+    if (GetDelegate()) { GetDelegate()->OnResized(old_w, old_h); }
+    // ATOMIC END
+
 }
 }
 
 
 void TBLayout::OnInflateChild(TBWidget *child)
 void TBLayout::OnInflateChild(TBWidget *child)

+ 5 - 0
Source/ThirdParty/TurboBadger/tb_scroll_container.cpp

@@ -312,6 +312,11 @@ void TBScrollContainer::OnResized(int old_w, int old_h)
     InvalidateLayout(INVALIDATE_LAYOUT_TARGET_ONLY);
     InvalidateLayout(INVALIDATE_LAYOUT_TARGET_ONLY);
     SizeConstraints sc(GetRect().w, GetRect().h);
     SizeConstraints sc(GetRect().w, GetRect().h);
     ValidateLayout(sc);
     ValidateLayout(sc);
+
+    // ATOMIC BEGIN  So pure UIWidgets can handle resize
+    if (GetDelegate()) { GetDelegate()->OnResized(old_w, old_h); }
+    // ATOMIC END
+
 }
 }
 
 
 }; // namespace tb
 }; // namespace tb

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

@@ -1017,6 +1017,10 @@ void TBWidget::OnPaintChildren(const PaintProps &paint_props)
 
 
 void TBWidget::OnResized(int old_w, int old_h)
 void TBWidget::OnResized(int old_w, int old_h)
 {
 {
+    // ATOMIC BEGIN  So pure UIWidgets can handle resize
+    if (GetDelegate()) { GetDelegate()->OnResized(old_w, old_h); }
+    // ATOMIC END
+
     int dw = m_rect.w - old_w;
     int dw = m_rect.w - old_w;
     int dh = m_rect.h - old_h;
     int dh = m_rect.h - old_h;
     for (TBWidget *child = GetFirstChild(); child; child = child->GetNext())
     for (TBWidget *child = GetFirstChild(); child; child = child->GetNext())
@@ -1038,6 +1042,7 @@ void TBWidget::OnResized(int old_w, int old_h)
 
 
         child->SetRect(rect);
         child->SetRect(rect);
     }
     }
+
 }
 }
 
 
 void TBWidget::OnInflateChild(TBWidget *child)
 void TBWidget::OnInflateChild(TBWidget *child)

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

@@ -354,14 +354,16 @@ enum WIDGET_HIT_STATUS {
     WIDGET_HIT_STATUS_HIT_NO_CHILDREN		///< The widget was hit, no children should be hit.
     WIDGET_HIT_STATUS_HIT_NO_CHILDREN		///< The widget was hit, no children should be hit.
 };
 };
 
 
-// ATOMIC: this must only be used by UIWidget, as we are casting to it
+// ATOMIC BEGIN: this must only be used by UIWidget, as we are casting to it
 class TBWidgetDelegate
 class TBWidgetDelegate
 {
 {
 public:
 public:
     virtual bool OnEvent(const TBWidgetEvent &ev) = 0;
     virtual bool OnEvent(const TBWidgetEvent &ev) = 0;
     virtual void OnFocusChanged(bool focused) = 0;
     virtual void OnFocusChanged(bool focused) = 0;
     virtual void OnDelete() = 0;
     virtual void OnDelete() = 0;
+    virtual void OnResized(int old_w, int old_h) = 0;
 };
 };
+// ATOMIC END
 
 
 /** The base TBWidget class.
 /** The base TBWidget class.
     Make a subclass to implement UI controls.
     Make a subclass to implement UI controls.