/// <summary> /// returns the current visible top row of buttons /// </summary> private void UpdateTopRow() { if (_count == 0) //There are no buttons in the grid { return; } if (_count == 1) { VisibleTopRow = new List <IterableButton>(1); VisibleTopRow.Add(_rootButton); return; } IterableButton button = _rootButton; //traverse the left column starting from the top, break on first visible button for (int i = 0; i < LeftColumn.Count; i++) { button = LeftColumn[i]; if (ButtonGridTools.CheckIfButtonOutofBoundsTop(_gridLayout, _groupScrollRect, ParentRectTransform, button)) { break; } } if (button != null) { //traverse the row the button is in int index = button.RowIndex; for (int i = 0; i < Grid[index].Count; i++) { VisibleTopRow.Add(Grid[index].Row[i]); } } }
/// <summary> /// Insert a new button into the grid and update navigation /// </summary> /// <returns></returns> public IterableButton InsertNewButton() { IterableButton button = InsertNewButtonNoNavUpdate(); StartCoroutine(UpdateGridNav()); return(button); }
/// <summary> /// Updates the left and right navigations component of the passed IterableButton "removeButton" /// </summary> /// <param name="removedButton"></param> private void UpdateNavigationAfterButtonRemove(IterableButton removedButton) { Navigation removedButtonNav = removedButton.Navigation; if (removedButtonNav.selectOnRight != null) { IterableButton rightButton = removedButtonNav.selectOnRight.GetComponent <IterableButton>(); Navigation updatedRightButtonNavigation = rightButton.Navigation; updatedRightButtonNavigation.selectOnLeft = null; if (removedButtonNav.selectOnLeft != null) { IterableButton leftButton = removedButtonNav.selectOnLeft.GetComponent <IterableButton>(); Navigation updatedLeftButtonNavigation = leftButton.Navigation; updatedLeftButtonNavigation.selectOnRight = rightButton.Button; updatedRightButtonNavigation.selectOnLeft = leftButton.Button; } rightButton.Navigation = updatedRightButtonNavigation; } if (removedButtonNav.selectOnLeft != null) { IterableButton leftButton = removedButtonNav.selectOnLeft.GetComponent <IterableButton>(); Navigation updatedLeftButtonNavigation = leftButton.Navigation; updatedLeftButtonNavigation.selectOnRight = null; if (removedButtonNav.selectOnRight != null) { IterableButton rightButton = removedButtonNav.selectOnRight.GetComponent <IterableButton>(); Navigation updatedRightButtonNavigation = rightButton.Navigation; updatedLeftButtonNavigation.selectOnRight = rightButton.Button; updatedRightButtonNavigation.selectOnLeft = leftButton.Button; } leftButton.Navigation = updatedLeftButtonNavigation; } }
/// <summary> /// inserts an iterable button at position (row, column) /// </summary> /// <param name="button"></param> /// <param name="row"></param> /// <param name="column"></param> public void InsertAt(IterableButton button, int row, int column) { if (button == null) { string error = "InsertAt was passed a null " + typeof(IterableButton) + " in scene object " + name; throw new NullReferenceException(error); } if (row > Grid.Count - 1) { string error = "InsertAt was passed a row number " + row + " that is outofbounds in scene object " + name + ". Total number of rows" + "are " + Grid.Count; throw new IndexOutOfRangeException(error); } int maxButtonsPerRow = CalculateMaxButtonsPerRow(); int siblingIndex = maxButtonsPerRow * row + column; //this indexes the child in the scene button.SetRowAndColumnIndex(row, column); button.transform.SetSiblingIndex(siblingIndex); Grid[row].Row.Insert(row, button); //shift to the right, starting from the next column ShiftRight(button, row, column + 1); //UpdateNavigation(); _count++; }
public IterableButton RemoveButton(int index) { Row[index].Deactivate(); IterableButton returner = Row[index]; Row[index] = null; return(returner); }
/// <summary> /// Inserts a button into the grid, returning the Iterable button that was inserted /// </summary> /// <returns></returns> public IterableButton InsertNewButtonNoNavUpdate() { IterableButton button; if (_rootButton == null) //is there a root? { //check the inactive pool, does it have any usable items? if (InactiveButtonPool.Count > 0) { _rootButton = InactiveButtonPool[0]; _rootButton.SetRowAndColumnIndex(0, 0); } else { _rootButton = BuildIterableButton(0, 0); } if (Grid.Count != 0) { Grid[0].Row.Add(_rootButton); _lastRowUsed = Grid[0]; } else { ButtonRow newRow = new ButtonRow(_rootButton, 0); Grid.Add(newRow); _lastRowUsed = newRow; } button = _rootButton; EventSystem.current.SetSelectedGameObject(_rootButton.Button.gameObject); } else //yes. now check if its possible to insert this new button into the last row that was used. { IterableButton newIterableButton; //first, check if there are too many buttons in the last row used. if there are none, insert this button, then update navigation pointers if (_lastRowUsed.Count < MaxButtonsPerRow) { int newColumnIndex = _lastRowUsed.Count; int rowIndex = _lastRowUsed.RowId; newIterableButton = BuildIterableButton(rowIndex, newColumnIndex); _lastRowUsed.Add(newIterableButton); } else { const int newColumnId = 0; int rowId = _lastRowUsed.RowId + 1; newIterableButton = BuildIterableButton(rowId, newColumnId); ButtonRow newButtonRow = new ButtonRow(newIterableButton, rowId); Grid.Add(newButtonRow); _lastRowUsed = newButtonRow; } button = newIterableButton; } _count++; return(button); }
private void SetBottomRowNavtoAuto() { for (int i = 0; i < VisibleBottomRow.Count; i++) { IterableButton button = VisibleBottomRow[i]; Navigation newNav = new Navigation(); newNav.mode = Navigation.Mode.Automatic; button.Navigation = newNav; } }
/// <summary> ///helper method that removes a button and places it in the inactive pool /// </summary> /// <param name="br"></param> /// <param name="columnId"></param> private void RemoveButton(ButtonRow br, int columnId) { IterableButton removedButton = br.RemoveButton(columnId); //update its navigation InactiveButtonPool.Add(removedButton); removedButton.transform.SetAsLastSibling(); UpdateNavigationAfterButtonRemove(removedButton); }
public ButtonRow(Button button, int buttonRow, int buttonColumn, int rowId) { IterableButton newButtonStructure = new IterableButton() { Button = button, ColumnIndex = buttonColumn, RowIndex = buttonRow }; Row.Add(newButtonStructure); RowId = rowId; }
/// <summary> /// If the field Button prefab is set to null, create a generic button, returning its IterableButton component /// </summary> /// <param name="rowId"></param> /// <param name="columnId"></param> /// <returns></returns> private IterableButton BuildIterableButton(int rowId, int columnId) { //lets check the inactive pool first if (InactiveButtonPool.Count == 0) { if (ButtonPrefab == null) { var emptyGameObject = new GameObject("Button"); emptyGameObject.transform.SetParent(ParentRectTransform); emptyGameObject.AddComponent <Image>(); Button button = emptyGameObject.AddComponent <Button>(); ColorBlock colors = button.colors; colors.highlightedColor = HighlightedButtonColor; button.colors = colors; IterableButton b = emptyGameObject.AddComponent <IterableButton>(); b.Init(rowId, columnId, button); b.transform.SetAsLastSibling(); return(b); } { try { GameObject go = Instantiate(ButtonPrefab); go.transform.SetParent(ParentRectTransform); IterableButton b = go.AddComponent <IterableButton>(); Button button = GetComponent <Button>(); ColorBlock colors = button.colors; colors.highlightedColor = HighlightedButtonColor; button.colors = colors; b.Init(rowId, columnId, button); b.transform.SetAsLastSibling(); return(b); } catch (NoButtonAttachedToPrefabException ex) { Debug.Log(ex.StackTrace); throw; } } } else //return one of the iterable buttons in the pool { IterableButton b = InactiveButtonPool[0]; b.Activate(); b.transform.SetAsLastSibling(); b.SetRowAndColumnIndex(rowId, columnId); InactiveButtonPool.RemoveAt(0); return(b); } }
private void SetColumnsNavToAuto() { for (int i = 0; i < LeftColumn.Count; i++) { IterableButton button = LeftColumn[i]; Navigation newNav = new Navigation(); newNav.mode = Navigation.Mode.Automatic; button.Navigation = newNav; } for (int i = 0; i < RightColumn.Count; i++) { IterableButton button = RightColumn[i]; Navigation newNav = new Navigation(); newNav.mode = Navigation.Mode.Automatic; button.Navigation = newNav; } }
private void UpdateBottomRow() { if (_count == 0) //There are no buttons in the grid { return; } if (_count == 1) { VisibleBottomRow = new List <IterableButton>(1); VisibleBottomRow.Add(_rootButton); return; } IterableButton button = _rootButton; //traverse the left column starting from the bottom, break on first visible button for (int i = LeftColumn.Count - 1; i >= 0; i--) { try { button = LeftColumn[i]; } catch (Exception) { Debug.Log("da"); } button = LeftColumn[i]; if (ButtonGridTools.CheckIfButtonOutBoundsBottom(_gridLayout, _groupScrollRect, ParentRectTransform, button)) { break; } } if (button != null) { //traverse the row the button is in int index = button.RowIndex; for (int i = 0; i < Grid[index].Count; i++) { Debug.Log(i); VisibleBottomRow.Add(Grid[index].Row[i]); } } }
void LateUpdate() { if (_debug) { Debug.Log("startit"); } //check what the current selected game object is GameObject currentSelectedGameObject = EventSystem.current.currentSelectedGameObject; //get the iterable button if (currentSelectedGameObject != null) { IterableButton currentButton = currentSelectedGameObject.GetComponent <IterableButton>(); //check if this button has changed since the last frame if (currentButton != null && currentButton == _previousButton && !_isRepositioningParent) { if (ButtonGridTools.CheckIfButtonOutofBoundsTop(_gridLayoutGroup, _scrollRect, _parentRectTransform, currentButton)) { _isRepositioningParent = true; Debug.Log("here1"); StartCoroutine(RepositionParent(currentButton.RectTransform.position)); } else if (ButtonGridTools.CheckIfButtonOutBoundsBottom(_gridLayoutGroup, _scrollRect, _parentRectTransform, currentButton)) { _isRepositioningParent = true; Debug.Log("here"); StartCoroutine(RepositionParent(currentButton.RectTransform.position)); } } _previousButton = currentButton; } if (currentSelectedGameObject == null) { _previousButton = null; } //check if current button is visible }
/// <summary> /// from the given row and column, shift all the elements left /// </summary> /// <param name="row"></param> /// <param name="column"></param> public void RemoveElementAndShiftLeft(int row, int column) { RemoveButton(Grid[row], column); bool beginRun = false; //shift elements to the left for (int i = row; i < Grid.Count; i++) { for (int j = !beginRun ? column : 0; j < MaxButtonsPerRow; j++) { beginRun = true; //check if were at the last column if (j == MaxButtonsPerRow - 1) { //check if i isn't at the last row //check if we have a bottom row underneath //and the number of elements are greater than 0. if (i < Grid.Count - 1 && Grid[i + 1] != null && Grid[i + 1].Row.Count > 0) { Grid[i].Row[j] = Grid[i + 1].Row[0]; Grid[i].Row[j].SetRowAndColumnIndex(i, j); } else if (i == Grid.Count - 1) //if we are at the last row, remove element at i,j { RemoveButton(Grid[i], j); //check if there are anymore elements in the list if (Grid[i].Count == 0) { Grid.RemoveAt(i); // Grid[i] = null; } break; } } //check if the column is not at the last index //check if the next element in the list is null. this means that there are no more elements that need to be shifted else if (j < MaxButtonsPerRow - 1 && Grid[i].Row[j + 1] == null) { RemoveButton(Grid[i], j); // Grid[i].Row[j] = null; break; } else { Grid[i].Row[j] = Grid[i].Row[j + 1]; Grid[i].Row[j].SetRowAndColumnIndex(i, j); } } } //set the root\ if (Grid.Count > 0) { if (Grid[0].Count > 0) { _rootButton = Grid[0].Row[0]; } else if (Grid[0].Count == 0) { _rootButton = null; } } // UpdateNavigation(); _count--; }
/// <summary> /// Shifts the buttons to the right starting at index row, column /// </summary> /// <param name="button"></param> /// <param name="row"></param> /// <param name="column"></param> private void ShiftRight(IterableButton button, int row, int column) { if (button == null) { string error = "InsertAt was passed a null " + typeof(IterableButton) + " in scene object " + name; throw new NullReferenceException(error); } int totalNumOfRows = Grid.Count; if (column > totalNumOfRows) { string error = "the row number " + row + " passed in ShiftRight() in scene object " + name + " is pointing to a non existent row. The total number of rows are " + totalNumOfRows; throw new IndexOutOfRangeException(error); } int maxElementsPerRow = CalculateMaxButtonsPerRow(); bool beginRun = false; for (int i = row; i < totalNumOfRows; i++) { for (int j = !beginRun ? column : 0; j < Grid[i].Count; j++) { beginRun = true; #region first check: check if the request row is > than the maxElement per row if (j >= maxElementsPerRow) //check if the request row is > than the maxElement per row { //check if its null. Remove and break if (Grid[i].Row[j] == null) { Grid[i].Row.RemoveAt(j); break; } if (i < Grid.Count - 1) //check if there is another row { //store the iterable button into a temp variable IterableButton temp = Grid[i].Row[j]; //add it to the next Row Grid[i + 1].Row.Insert(0, temp); //remove the button from the current row Grid[i].Row.RemoveAt(j); break; } //then we're at the last row. Add new row if (i == Grid.Count - 1) { //store the iterable button into a temp variable IterableButton temp = Grid[i].Row[j]; //build a new row and add the temp into this row ButtonRow newRow = BuildButtonRow(1); Grid.Add(newRow); totalNumOfRows++; newRow.Add(temp); //remove the button from the current row Grid[i].Row.RemoveAt(j); break; } } #endregion //ok, since the first check is made, we just need to update the row and column numbers of each element Grid[i].Row[j].SetRowAndColumnIndex(i, j); } } }
public void Add(IterableButton newIterableButton) { Row.Add(newIterableButton); }
public ButtonRow(IterableButton buttonStructure, int rowId) { Row.Add(buttonStructure); RowId = rowId; }
public void Remove(IterableButton b) { if (Count > 0) { } }
protected bool Equals(IterableButton obj) { return(base.Equals(obj) && Equals(Button, obj.Button)); }
public static bool CheckIfButtonOutofBoundsTop(GridLayoutGroup layoutGroup, ScrollRect scrollRect, RectTransform scrollRectsParent, IterableButton button) { //calculate the vertical bound of the button. Its height is set by the grid layout group float buttonHalfHeight = layoutGroup.cellSize.y / 2; float verticalButtonPadding = layoutGroup.padding.top; float upperButtonBounds = button.transform.position.y + buttonHalfHeight + verticalButtonPadding; float upperBounds = scrollRect.transform.position.y + (scrollRectsParent.rect.height / 2); return(upperButtonBounds > upperBounds); }
/// <summary> /// Helper method that updates a given button's navigation. Needs to be called whenever a /// button's position shifts over /// </summary> /// <param name="button"></param> private void UpdateNavigation(IterableButton button) { Navigation updatedNavigation = new Navigation(); updatedNavigation.mode = Navigation.Mode.Explicit; //where is the element located in the Grid? int row = button.RowIndex; int column = button.ColumnIndex; Debug.Log("row: " + row + " Column " + column); if (row == 0) { if (column == 0) { //check if there is a row below if (Grid.Count == 1) { updatedNavigation.selectOnDown = null; } else { updatedNavigation.selectOnDown = Grid[row + 1].Row[column].Button; //update the top row's navigation to point to this button Navigation nextUpdatedNav = Grid[row + 1].Row[column].Navigation; nextUpdatedNav.mode = Navigation.Mode.Explicit; nextUpdatedNav.selectOnUp = Grid[row].Row[column].Button; Grid[row + 1].Row[column].Navigation = nextUpdatedNav; } if (Grid[row].Row.Count != 1) { updatedNavigation.selectOnRight = Grid[row].Row[column + 1].Button; //update the right columns's navigation selectOnLeft to point to this button Navigation nextUpdatedNav = Grid[row].Row[column + 1].Navigation; nextUpdatedNav.mode = Navigation.Mode.Explicit; nextUpdatedNav.selectOnLeft = Grid[row].Row[column].Button; Grid[row].Row[column + 1].Navigation = nextUpdatedNav; } } else if (column == Grid[row].Row.Count - 1) { updatedNavigation.selectOnRight = null; if (Grid[row].Row.Count != 1) { updatedNavigation.selectOnLeft = Grid[row].Row[column - 1].Button; //update the left columns's navigation selectOnRight to point to this button Navigation nextUpdatedNav = Grid[row].Row[column - 1].Navigation; nextUpdatedNav.mode = Navigation.Mode.Explicit; nextUpdatedNav.selectOnRight = Grid[row].Row[column].Button; Grid[row].Row[column - 1].Navigation = nextUpdatedNav; } } else { //update the right columns's navigation selectOnLeft to point to this button updatedNavigation.selectOnRight = Grid[row].Row[column + 1].Button; Navigation nextUpdatedNav = Grid[row].Row[column + 1].Navigation; nextUpdatedNav.mode = Navigation.Mode.Explicit; nextUpdatedNav.selectOnLeft = Grid[row].Row[column].Button; Grid[row].Row[column + 1].Navigation = nextUpdatedNav; //update the left columns's navigation selectOnRight to point to this button updatedNavigation.selectOnLeft = Grid[row].Row[column - 1].Button; Navigation next2UpdatedNav = Grid[row].Row[column - 1].Navigation; next2UpdatedNav.mode = Navigation.Mode.Explicit; next2UpdatedNav.selectOnRight = Grid[row].Row[column].Button; Grid[row].Row[column - 1].Navigation = next2UpdatedNav; } if (Grid.Count > 1) { if (column < Grid[row + 1].Count) { updatedNavigation.selectOnDown = Grid[row + 1].Row[column].Button; //update the bottom rows columns's navigation selectOnUp to point to this button Navigation next2UpdatedNav = Grid[row + 1].Row[column].Navigation; next2UpdatedNav.mode = Navigation.Mode.Explicit; next2UpdatedNav.selectOnUp = Grid[row].Row[column].Button; Grid[row + 1].Row[column].Navigation = next2UpdatedNav; } } } //check if count isn't equal to 1 because the previous check already performed the necessary navigation modifications else if (row == Grid.Count - 1 && Grid.Count != 1) { updatedNavigation.selectOnDown = null; updatedNavigation.selectOnUp = Grid[row - 1].Row[column].Button; //update the left columns's navigation selectOnDown to point to this button Navigation updatedNav = Grid[row - 1].Row[column].Navigation; updatedNav.mode = Navigation.Mode.Explicit; updatedNav.selectOnDown = Grid[row].Row[column].Button; Grid[row - 1].Row[column].Navigation = updatedNav; if (column != 0) { updatedNavigation.selectOnLeft = Grid[row].Row[column - 1].Button; //update the left columns's navigation selectOnRight to point to this button Navigation next2UpdatedNav = Grid[row].Row[column - 1].Navigation; next2UpdatedNav.mode = Navigation.Mode.Explicit; next2UpdatedNav.selectOnRight = Grid[row].Row[column].Button; Grid[row].Row[column - 1].Navigation = next2UpdatedNav; } if (column == Grid[row].Row.Count - 1) { updatedNavigation.selectOnRight = null; } else { updatedNavigation.selectOnRight = Grid[row].Row[column + 1].Button; //update the right columns's navigation selectOnUp to point to this button Navigation next2UpdatedNav = Grid[row].Row[column + 1].Navigation; next2UpdatedNav.mode = Navigation.Mode.Explicit; next2UpdatedNav.selectOnLeft = Grid[row].Row[column].Button; Grid[row].Row[column + 1].Navigation = next2UpdatedNav; } button.Button.navigation = updatedNavigation; } else { updatedNavigation.selectOnUp = Grid[row - 1].Row[column].Button; //need to check if we can select on down if (column < Grid[row + 1].Count) { updatedNavigation.selectOnDown = Grid[row + 1].Row[column].Button; } updatedNavigation.selectOnLeft = column == 0 ? null : Grid[row].Row[column - 1].Button; updatedNavigation.selectOnRight = column == Grid[row].Row.Count - 1 ? null : Grid[row].Row[column + 1].Button; } //check if row is thefirst, then the left needs to point to the last element of the previous row and the afformentioned element would point to this one if (column == 0 && row > 0) { updatedNavigation.selectOnLeft = Grid[row - 1].Row[Grid[row - 1].Count - 1].Button; Navigation next2UpdatedNav = Grid[row - 1].Row[Grid[row - 1].Count - 1].Navigation; next2UpdatedNav.mode = Navigation.Mode.Explicit; next2UpdatedNav.selectOnRight = Grid[row].Row[column].Button; Grid[row - 1].Row[Grid[row - 1].Count - 1].Navigation = next2UpdatedNav; } button.Navigation = updatedNavigation; }
/// <summary> /// update the horizontal navigation of an iterable button in the grid /// </summary> /// <param name="button"></param> private void UpdateHorizontalNavigation(IterableButton button) { Navigation updatedNavigation = button.Navigation; updatedNavigation.mode = Navigation.Mode.Explicit; //where is the element located in the Grid? int row = button.RowIndex; int column = button.ColumnIndex; //update left and right if (column == 0) { if (row == 0) //top left --> left pointer points to bottom right most column { if (WrapHorizontalNavigation) { updatedNavigation.selectOnLeft = Grid[Grid.Count - 1].Row[Grid[Grid.Count - 1].Row.Count - 1].Button; } //point to right if count > 0, else point to self if (Grid[row].Count > 1) { updatedNavigation.selectOnRight = Grid[row].Row[column + 1].Button; } else if (WrapHorizontalNavigation) { updatedNavigation.selectOnRight = Grid[0].Row[0].Button; } } else if (row > 0) { if (WrapHorizontalNavigation) { //check if there is a row above ButtonRow br = Grid[row - 1]; int lastIndex = br.Count - 1; updatedNavigation.selectOnLeft = br.Row[lastIndex].Button; } //check if a right pointer is possible and isnt' the last element if (Grid[row].Count > 1) { updatedNavigation.selectOnRight = Grid[row].Row[column + 1].Button; } else if (WrapHorizontalNavigation)//then point to the first element { updatedNavigation.selectOnRight = Grid[0].Row[0].Button; } } } else if (column < Grid[row].Row.Count - 1 && column > 0) { //update select on left updatedNavigation.selectOnLeft = Grid[row].Row[column - 1].Button; //update select on right updatedNavigation.selectOnRight = Grid[row].Row[column + 1].Button; } //finally if we're at the last element in the row else if (column == Grid[row].Row.Count - 1) { //point to the element on the left updatedNavigation.selectOnLeft = Grid[row].Row[column - 1].Button; //check if there are any rows below, then point to the first element of that row if (WrapHorizontalNavigation) { if (row < Grid.Count - 1) { updatedNavigation.selectOnRight = Grid[row + 1].Row[0].Button; } else //point to the first element { updatedNavigation.selectOnRight = Grid[0].Row[0].Button; } } } button.Navigation = updatedNavigation; }
/// <summary> /// Checks if the button is out of bounds from the button, from the scrollRectsParent /// </summary> /// <param name="layoutGroup"></param> /// <param name="scrollRect"></param> /// <param name="scrollRectsParent"></param> /// <param name="button"></param> /// <returns></returns> public static bool CheckIfButtonOutBoundsBottom(GridLayoutGroup layoutGroup, ScrollRect scrollRect, RectTransform scrollRectsParent, IterableButton button) { float buttonHalfHeight = layoutGroup.cellSize.y / 2; float verticalButtonPadding = layoutGroup.padding.bottom; float lowerButtonBound = button.RectTransform.position.y - buttonHalfHeight - verticalButtonPadding - layoutGroup.spacing.y; float lowerBounds = scrollRect.transform.position.y - (scrollRectsParent.rect.height / 2); return(lowerButtonBound < lowerBounds); }