diff --git a/Client/core/CSettings.cpp b/Client/core/CSettings.cpp index 78376876de..a0568da998 100644 --- a/Client/core/CSettings.cpp +++ b/Client/core/CSettings.cpp @@ -1272,8 +1272,11 @@ void CSettings::CreateGUI() * CEGUI tab. **/ m_pGridLayout = reinterpret_cast(pManager->CreateGridLayout(pTabCEGUI)); - m_pGridLayout->SetGrid(1, 1); - + m_pGridLayout->SetGrid(9, 9); + m_pGridLayout->SetColumnWidth(1, 0.25f); + m_pGridLayout->SetColumnWidth(3, 0.25f); + m_pGridLayout->SetRowHeight(2, 0.25f); + m_pGridLayout->SetRowHeight(4, 0.25f); vecTemp = CVector2D(12.f, 12.f); // Grid layout section label @@ -1336,14 +1339,22 @@ void CSettings::CreateGUI() m_pGridRowsValueLabel->SetHorizontalAlign(CGUI_ALIGN_LEFT); m_pCellAlpha->SetScrollPosition(0.5f); - m_pGridColumns->SetScrollPosition(0.2f); - m_pGridRows->SetScrollPosition(0.2f); + m_pGridColumns->SetScrollPosition(0.9f); + m_pGridRows->SetScrollPosition(0.9f); // Grid layout vecTemp.fY += 20.0f; m_pGridLayout->SetPosition(CVector2D(vecTemp.fX, vecTemp.fY)); m_pGridLayout->SetSize(CVector2D(500.0f, 300.0f)); + //m_pTestCellLabel = reinterpret_cast(pManager->CreateLabel(pTabCEGUI, _("Test cell"))); + //m_pTestCellLabel->AutoSize(); + //m_pTestCellLabel->SetHorizontalAlign(CGUI_ALIGN_HORIZONTALCENTER); + //m_pTestCellLabel->SetVerticalAlign(CGUI_ALIGN_VERTICALCENTER); + + //bool add = m_pGridLayout->AddItem(m_pTestCellLabel, 1, 1); + //m_pTestCellLabel->SetText(add ? "true" : "false"); + // Set up the events m_pWindow->SetEnterKeyHandler(GUI_CALLBACK(&CSettings::OnOKButtonClick, this)); m_pButtonOK->SetClickHandler(GUI_CALLBACK(&CSettings::OnOKButtonClick, this)); diff --git a/Client/gui/CGUIGridLayout_Impl.cpp b/Client/gui/CGUIGridLayout_Impl.cpp index 1682756b64..dbc4d3de3d 100644 --- a/Client/gui/CGUIGridLayout_Impl.cpp +++ b/Client/gui/CGUIGridLayout_Impl.cpp @@ -10,6 +10,7 @@ *****************************************************************************/ #include "StdInc.h" +#include #define CGUIGRIDLAYOUT_NAME "CGUI/FrameWindow" @@ -80,7 +81,6 @@ const bool CGUIGridLayout_Impl::AddItem(CGUIElement* item, int column, int row, item->SetParent(cell->container); item->SetPosition(CVector2D(0.0f, 0.0f), true); - item->SetSize(CVector2D(1.0f, 1.0f), true); item->ForceRedraw(); cell->element = item; @@ -174,17 +174,17 @@ SGridCellItem* CGUIGridLayout_Impl::GetCell(const CGUIElement* item) const return id == 0 ? nullptr : m_cells.at(id); } -std::vector CGUIGridLayout_Impl::GetCellsInColumn(const int column) +std::vector CGUIGridLayout_Impl::GetCellsInColumn(const int column) const { return GetCellsInGrid(column, 0, column, m_rows - 1); } -std::vector CGUIGridLayout_Impl::GetCellsInRow(const int row) +std::vector CGUIGridLayout_Impl::GetCellsInRow(const int row) const { return GetCellsInGrid(0, row, m_columns - 1, row); } -std::vector CGUIGridLayout_Impl::GetCellsInGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) +std::vector CGUIGridLayout_Impl::GetCellsInGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) const { if (startColumn < 1 || startRow < 1 || endColumn > m_columns || endRow > m_rows) { @@ -212,7 +212,7 @@ std::vector CGUIGridLayout_Impl::GetCellsInGrid(const int startC return cells; } -std::vector CGUIGridLayout_Impl::GetCellsOutsideGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) +std::vector CGUIGridLayout_Impl::GetCellsOutsideGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) const { if (startColumn < 1 || startRow < 1 || endColumn > m_columns || endRow > m_rows) { @@ -278,6 +278,9 @@ const bool CGUIGridLayout_Impl::SetGrid(int columns, int rows) m_grid[i].resize(rows, 0); } + m_columnWidths.resize(m_columns, 0.0f); + m_rowHeights.resize(m_rows, 0.0f); + if (larger) { CreateGridCells(); @@ -288,14 +291,14 @@ const bool CGUIGridLayout_Impl::SetGrid(int columns, int rows) } else { - CleanupGridItems(); + CleanupGridCells(); // Since the grid has been resized, we need to make sure the active cell is still within the grid m_activeColumn = std::min(m_activeColumn, columns); m_activeRow = std::min(m_activeRow, rows); } - RepositionGridItems(); + RepositionGridCells(); return true; } @@ -327,7 +330,7 @@ const bool CGUIGridLayout_Impl::SetActiveRow(int row) return true; } -const std::pair CGUIGridLayout_Impl::GetActiveCell() +const std::pair CGUIGridLayout_Impl::GetActiveCell() const { return std::make_pair(m_activeColumn, m_activeRow); } @@ -340,6 +343,7 @@ void CGUIGridLayout_Impl::SetItemAlignment(const CGUIElement* item, eGridLayoutI return; cell->alignment = alignment; + RepositionGridCell(*cell, true); } const eGridLayoutItemAlignment CGUIGridLayout_Impl::GetItemAlignment(const CGUIElement* item) const @@ -375,10 +379,34 @@ const bool CGUIGridLayout_Impl::SetDefaultCellAlpha(const float alpha) return true; } +const bool CGUIGridLayout_Impl::SetColumnWidth(const int column, const float width) +{ + if (!InColumnRange(column)) + return false; + + m_columnWidths[column - 1] = width; + RepositionGridCells(); + return true; +} + +const bool CGUIGridLayout_Impl::SetRowHeight(const int row, const float height) +{ + if (!InRowRange(row)) + return false; + + m_rowHeights[row - 1] = height; + RepositionGridCells(); + return true; +} + void CGUIGridLayout_Impl::CreateGridCells() { auto* parent = reinterpret_cast(this); + // Calculate our own offsets here for performance reasons + std::vector columnOffset(m_columns, 0.0f); + std::vector rowOffset(m_rows, 0.0f); + for (int i = 0; i < m_columns; i++) { for (int j = 0; j < m_rows; j++) @@ -387,44 +415,50 @@ void CGUIGridLayout_Impl::CreateGridCells() if (cell == 0) { - auto* cell = new SGridCellItem(); - cell->container = m_pManager->CreateStaticImage(parent); - cell->container->SetFrameEnabled(false); + auto* cellItem = new SGridCellItem(); + cellItem->container = m_pManager->CreateStaticImage(parent); + cellItem->alignment = m_defaultAlignment; // Assign the cell container texture, alternative between m_cellTexture and m_cellTextureAlt - cell->container->LoadFromTexture((i + j) % 2 == 0 ? m_cellTexture : m_cellTextureAlt); - cell->container->SetAlpha(m_defaultCellAlpha); + cellItem->container->LoadFromTexture((i + j) % 2 == 0 ? m_cellTexture : m_cellTextureAlt); + cellItem->container->SetAlpha(m_defaultCellAlpha); + + auto offsets = AccumulateOffsets({columnOffset, rowOffset}); // Position the cell container in the grid - cell->container->SetPosition(CVector2D(i * (1.0f / m_columns), j * (1.0f / m_rows)), true); + cellItem->container->SetPosition(CalculateCellPosition(*cellItem, offsets), true); // Size the cell container in the grid - cell->container->SetSize(CVector2D(1.0f / m_columns, 1.0f / m_rows), true); + cellItem->container->SetSize(CalculateCellSize(*cellItem, offsets), true); - cell->id = m_nextId; + cellItem->id = m_nextId; - auto* label = m_pManager->CreateLabel(cell->container, std::to_string(m_nextId).c_str()); + auto* label = m_pManager->CreateLabel(cellItem->container, std::to_string(m_nextId).c_str()); label->AutoSize(); - label->SetPosition(CVector2D(0.0f, 0.0f), true); - label->SetSize(CVector2D(1.0f, 1.0f), true); - label->SetHorizontalAlign(CGUI_ALIGN_HORIZONTALCENTER); - label->SetVerticalAlign(CGUI_ALIGN_VERTICALCENTER); - cell->element = label; - cell->column = i + 1; - cell->row = j + 1; - cell->alignment = m_defaultAlignment; + CVector2D offset = GetAlignmentOffset(*cellItem, label->GetSize(true)); + label->SetPosition(offset, true); + label->ForceRedraw(); + + cellItem->element = label; + cellItem->column = i + 1; + cellItem->row = j + 1; - m_cells.emplace(m_nextId, cell); + m_cells.emplace(m_nextId, cellItem); m_grid[i][j] = m_nextId; m_nextId++; } + + rowOffset[j] = m_rowHeights[j]; } + + columnOffset[i] = m_columnWidths[i]; + rowOffset.assign(m_rows, 0.0f); } } -void CGUIGridLayout_Impl::CleanupGridItems() +void CGUIGridLayout_Impl::CleanupGridCells() { for (auto& cell : m_cells) { @@ -449,20 +483,129 @@ void CGUIGridLayout_Impl::CleanupGridItems() } } -void CGUIGridLayout_Impl::RepositionGridItems() +const CVector2D CGUIGridLayout_Impl::CalculateCellPosition(const SGridCellItem& cell, const std::pair& offsets) const { - for (auto& cell : m_cells) + int widths = CountColumnWidths(); + int heights = CountRowHeights(); + + if (cell.element != nullptr) + cell.element->SetText(std::to_string(std::max(0, cell.column - widths)).c_str()); + + return CVector2D(offsets.first + (std::max(0, cell.column - CountColumnWidths(cell.column) - 1) * + ((1.0f - AccumulateOffset(m_columnWidths)) / (m_columns - widths))), + offsets.second + (std::max(0, cell.row - CountRowHeights(cell.row) - 1) * + ((1.0f - AccumulateOffset(m_rowHeights)) / (m_rows - heights)))); +} + +const CVector2D CGUIGridLayout_Impl::CalculateCellSize(const SGridCellItem& cell, const std::pair& offsets) const +{ + int widths = CountColumnWidths(); + int heights = CountRowHeights(); + + return CVector2D( + m_columnWidths[cell.column - 1] == 0.0f ? (1.0f - AccumulateOffset(m_columnWidths)) / (m_columns - widths) : m_columnWidths[cell.column - 1], + m_rowHeights[cell.row - 1] == 0.0f ? (1.0f - AccumulateOffset(m_rowHeights)) / (m_rows - heights) : m_rowHeights[cell.row - 1]); +} + +const std::pair, std::vector> CGUIGridLayout_Impl::CalculateGridOffsets(const int column, const int row) const +{ + std::vector columnOffset(m_columns, 0.0f); + std::vector rowOffset(m_rows, 0.0f); + + for (int i = 0; i < (column == 0 ? m_columns : column) - 1; i++) { - cell.second->container->SetPosition(CVector2D((cell.second->column - 1) * (1.0f / m_columns), (cell.second->row - 1) * (1.0f / m_rows)), true); - cell.second->container->SetSize(CVector2D(1.0f / m_columns, 1.0f / m_rows), true); + for (int j = 0; j < (row == 0 ? m_rows : row) - 1; j++) + { + if (j < (row == 0 ? m_rows : row)) + { + rowOffset[j + 1] = m_rowHeights[j]; + } + } + + columnOffset[i + 1] = m_columnWidths[i]; + rowOffset.assign(m_rows, 0.0f); + } + + return {columnOffset, rowOffset}; +} + +const float CGUIGridLayout_Impl::AccumulateOffset(const std::vector& offset) const +{ + return std::reduce(offset.begin(), offset.end()); +} + +const std::pair CGUIGridLayout_Impl::AccumulateOffsets(const std::pair, std::vector>& offsets) const +{ + return {AccumulateOffset(offsets.first), AccumulateOffset(offsets.second)}; +} + +void CGUIGridLayout_Impl::RepositionGridCells(const bool itemOnly) const +{ + std::vector columnOffset(m_columns, 0.0f); + std::vector rowOffset(m_rows, 0.0f); - if (cell.second->element != nullptr) + for (int i = 0; i < m_columns; i++) + { + for (int j = 0; j < m_rows; j++) { - cell.second->element->SetPosition(CVector2D(0.0f, 0.0f), true); - cell.second->element->SetSize(CVector2D(1.0f, 1.0f), true); - cell.second->element->ForceRedraw(); + const auto cell = m_cells.count(m_grid[i][j]); + + if (cell != 0) + { + const auto& cellItem = m_cells.at(m_grid[i][j]); + + if (!itemOnly) + { + auto offsets = AccumulateOffsets({columnOffset, rowOffset}); + + cellItem->container->SetPosition(CalculateCellPosition(*cellItem, offsets), true); + cellItem->container->SetSize(CalculateCellSize(*cellItem, offsets), true); + cellItem->container->ForceRedraw(); + } + + if (cellItem->element != nullptr) + { + CVector2D position = GetAlignmentOffset(*cellItem, cellItem->element->GetSize(true)); + cellItem->element->SetPosition(position, true); + cellItem->element->ForceRedraw(); + } + } + + rowOffset[j] = m_rowHeights[j]; } + + columnOffset[i] = m_columnWidths[i]; + rowOffset.assign(m_rows, 0.0f); + } +} + +void CGUIGridLayout_Impl::RepositionGridCell(const SGridCellItem& cell, const bool itemOnly) const +{ + if (!itemOnly) + { + auto offsets = AccumulateOffsets(CalculateGridOffsets(cell.column, cell.row)); + + cell.container->SetPosition(CalculateCellPosition(cell, offsets), true); + cell.container->SetSize(CalculateCellSize(cell, offsets), true); + cell.container->ForceRedraw(); } + + if (cell.element != nullptr) + { + CVector2D position = GetAlignmentOffset(cell, cell.element->GetSize(true)); + cell.element->SetPosition(position, true); + cell.element->ForceRedraw(); + } +} + +void CGUIGridLayout_Impl::RepositionGridCell(const int column, const int row, const bool itemOnly) const +{ + const auto* cell = GetCell(column, row); + + if (cell == nullptr) + return; + + RepositionGridCell(*cell); } const bool CGUIGridLayout_Impl::InGridRange(const int column, const int row) const @@ -479,3 +622,53 @@ const bool CGUIGridLayout_Impl::InRowRange(const int row) const { return row >= 1 && row <= m_rows; } + +const CVector2D CGUIGridLayout_Impl::GetAlignmentOffset(const SGridCellItem& cell, const CVector2D& size) const +{ + CVector2D offset; + + switch (cell.alignment) + { + case eGridLayoutItemAlignment::TOP_LEFT: + offset = CVector2D(0.0f, 0.0f); + break; + case eGridLayoutItemAlignment::TOP_CENTER: + offset = CVector2D((1.0f - size.fX) / 2.0f, 0.0f); + break; + case eGridLayoutItemAlignment::TOP_RIGHT: + offset = CVector2D(1.0f - size.fX, 0.0f); + break; + case eGridLayoutItemAlignment::MIDDLE_LEFT: + offset = CVector2D(0.0f, (1.0f - size.fY) / 2.0f); + break; + case eGridLayoutItemAlignment::MIDDLE_CENTER: + offset = CVector2D((1.0f - size.fX) / 2.0f, (1.0f - size.fY) / 2.0f); + break; + case eGridLayoutItemAlignment::MIDDLE_RIGHT: + offset = CVector2D(1.0f - size.fX, (1.0f - size.fY) / 2.0f); + break; + case eGridLayoutItemAlignment::BOTTOM_LEFT: + offset = CVector2D(0.0f, 1.0f - size.fY); + break; + case eGridLayoutItemAlignment::BOTTOM_CENTER: + offset = CVector2D((1.0f - size.fX) / 2.0f, 1.0f - size.fY); + break; + case eGridLayoutItemAlignment::BOTTOM_RIGHT: + offset = CVector2D(1.0f - size.fX, 1.0f - size.fY); + break; + } + + return offset; +} + +const int CGUIGridLayout_Impl::CountColumnWidths(const int maxColumns) const +{ + return std::count_if(m_columnWidths.begin(), m_columnWidths.begin() + (maxColumns == 0 || maxColumns < 1 ? m_columns : maxColumns) - 1, + [&](const float& width) { return width > 0.0f; }); +} + +const int CGUIGridLayout_Impl::CountRowHeights(const int maxRows) const +{ + return std::count_if(m_rowHeights.begin(), m_rowHeights.begin() + (maxRows == 0 || maxRows < 1 ? m_rows : maxRows) - 1, + [&](const float& height) { return height > 0.0f; }); +} diff --git a/Client/gui/CGUIGridLayout_Impl.h b/Client/gui/CGUIGridLayout_Impl.h index 1d62918e9c..d2a699d480 100644 --- a/Client/gui/CGUIGridLayout_Impl.h +++ b/Client/gui/CGUIGridLayout_Impl.h @@ -33,7 +33,7 @@ class CGUIGridLayout_Impl : public CGUIGridLayout, public CGUIElement_Impl const int GetActiveColumn() const { return m_activeColumn; } const int GetActiveRow() const { return m_activeRow; } - const std::pair GetActiveCell(); + const std::pair GetActiveCell() const; const bool AddItem(CGUIElement* item, int column, int row, const bool moveToNextCell = true); const bool AddItem(CGUIElement* item, const bool moveToNextCell = true); @@ -44,10 +44,10 @@ class CGUIGridLayout_Impl : public CGUIGridLayout, public CGUIElement_Impl SGridCellItem* GetCell(const int column, const int row) const; SGridCellItem* GetCell(const CGUIElement* item) const; - std::vector GetCellsInGrid(const int startColumn, const int startRow, const int endColumn, const int endRow); - std::vector GetCellsOutsideGrid(const int startColumn, const int startRow, const int endColumn, const int endRow); - std::vector GetCellsInColumn(const int column); - std::vector GetCellsInRow(const int row); + std::vector GetCellsInGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) const; + std::vector GetCellsOutsideGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) const; + std::vector GetCellsInColumn(const int column) const; + std::vector GetCellsInRow(const int row) const; void SetItemAlignment(const CGUIElement* item, eGridLayoutItemAlignment alignment); void SetDefaultItemAlignment(eGridLayoutItemAlignment alignment) { m_defaultAlignment = alignment; } @@ -58,6 +58,9 @@ class CGUIGridLayout_Impl : public CGUIGridLayout, public CGUIElement_Impl const bool SetCellAlpha(const int column, const int row, const float alpha); const bool SetDefaultCellAlpha(const float alpha); + const bool SetColumnWidth(const int column, const float width); + const bool SetRowHeight(const int row, const float height); + #include "CGUIElement_Inc.h" private: @@ -75,16 +78,34 @@ class CGUIGridLayout_Impl : public CGUIGridLayout, public CGUIElement_Impl std::unordered_map m_cells; std::unordered_map m_items; + std::vector m_columnWidths; + std::vector m_rowHeights; + CGUITexture* m_cellTexture = nullptr; CGUITexture* m_cellTextureAlt = nullptr; eGridLayoutItemAlignment m_defaultAlignment = eGridLayoutItemAlignment::MIDDLE_CENTER; void CreateGridCells(); - void CleanupGridItems(); - void RepositionGridItems(); + void CleanupGridCells(); + + void RepositionGridCells(const bool itemOnly = false) const; + void RepositionGridCell(const SGridCellItem& cell, const bool itemOnly = false) const; + void RepositionGridCell(const int column, const int row, const bool itemOnly = false) const; const bool InGridRange(const int column, const int row) const; const bool InColumnRange(const int column) const; const bool InRowRange(const int row) const; + + const CVector2D CalculateCellPosition(const SGridCellItem& cell, const std::pair& offsets) const; + const CVector2D CalculateCellSize(const SGridCellItem& cell, const std::pair& offset) const; + + const std::pair, std::vector> CalculateGridOffsets(const int column = 0, const int row = 0) const; + const std::pair AccumulateOffsets(const std::pair, std::vector>& offsets) const; + const float AccumulateOffset(const std::vector& offset) const; + + const int CountColumnWidths(const int maxColumns = 0) const; + const int CountRowHeights(const int maxRows = 0) const; + + const CVector2D GetAlignmentOffset(const SGridCellItem& cell, const CVector2D& size) const; }; diff --git a/Client/sdk/gui/CGUIGridLayout.h b/Client/sdk/gui/CGUIGridLayout.h index 05833b7ac0..af0f5d1cd6 100644 --- a/Client/sdk/gui/CGUIGridLayout.h +++ b/Client/sdk/gui/CGUIGridLayout.h @@ -59,7 +59,7 @@ class CGUIGridLayout : public CGUIElement virtual const int GetActiveColumn() const = 0; virtual const int GetActiveRow() const = 0; - virtual const std::pair GetActiveCell() = 0; + virtual const std::pair GetActiveCell() const = 0; virtual const bool AddItem(CGUIElement* item, int column, int row, const bool moveToNextCell = true) = 0; virtual const bool AddItem(CGUIElement* item, const bool moveToNextCell = true) = 0; @@ -70,10 +70,10 @@ class CGUIGridLayout : public CGUIElement virtual SGridCellItem* GetCell(const int column, const int row) const = 0; virtual SGridCellItem* GetCell(const CGUIElement* item) const = 0; - virtual std::vector GetCellsInGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) = 0; - virtual std::vector GetCellsOutsideGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) = 0; - virtual std::vector GetCellsInColumn(const int column) = 0; - virtual std::vector GetCellsInRow(const int row) = 0; + virtual std::vector GetCellsInGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) const = 0; + virtual std::vector GetCellsOutsideGrid(const int startColumn, const int startRow, const int endColumn, const int endRow) const = 0; + virtual std::vector GetCellsInColumn(const int column) const = 0; + virtual std::vector GetCellsInRow(const int row) const = 0; virtual void SetItemAlignment(const CGUIElement* item, eGridLayoutItemAlignment alignment) = 0; virtual void SetDefaultItemAlignment(eGridLayoutItemAlignment alignment) = 0; @@ -83,4 +83,7 @@ class CGUIGridLayout : public CGUIElement virtual const bool SetCellAlpha(const int column, const int row, const float alpha) = 0; virtual const bool SetDefaultCellAlpha(const float alpha) = 0; + + virtual const bool SetColumnWidth(const int column, const float width) = 0; + virtual const bool SetRowHeight(const int row, const float height) = 0; };