2026-04-18 20:51:45 +03:00
# include "GridScrollArea.hpp"
# include "../ElementHelpers/ScrollAreaHelpers.hpp"
# include "Helpers/ConvertVec.hpp"
# include "../GUIManager.hpp"
namespace GUIStuff {
GridScrollArea : : GridScrollArea ( GUIManager & gui ) : Element ( gui ) { }
2026-04-19 10:03:57 +03:00
void GridScrollArea : : layout ( const Clay_ElementId & id , const Options & o ) {
2026-04-18 20:51:45 +03:00
using namespace ElementHelpers ;
2026-04-19 10:03:57 +03:00
options = o ;
2026-04-22 17:40:58 +03:00
if ( boundingBox . has_value ( ) )
rowWidth = boundingBox . value ( ) . width ( ) ; // Use grid element bounding box instead of inner content width because row width will decide whether a scroll bar appears or not, which will change the inner content width (circular dependency)
2026-04-18 20:51:45 +03:00
ScrollBarManyEntriesOptions opts ;
opts . clipHorizontal = true ;
opts . entryHeight = options . entryHeight ;
opts . innerContentExtraCallback = [ & , extraCallback = options . innerContentExtraCallback ] ( const ScrollArea : : InnerContentParameters & contParams ) {
if ( extraCallback ) extraCallback ( contParams ) ;
} ;
2026-04-21 18:38:24 +03:00
size_t entriesPerRow = std : : max < size_t > ( rowWidth / options . entryWidth , 1 ) ;
2026-04-19 10:03:57 +03:00
size_t rowCount = ( options . entryCount + entriesPerRow - 1 ) / entriesPerRow ;
2026-04-18 20:51:45 +03:00
opts . entryCount = rowCount ;
2026-04-28 20:55:30 +03:00
2026-04-21 18:38:24 +03:00
uint16_t xPadding = 0 ;
2026-04-28 20:55:30 +03:00
uint16_t xChildGap = 0 ;
float entryWidth = options . entryWidth ;
if ( rowCount > 1 | | ( rowCount = = 1 & & ( ( options . entryCount + entriesPerRow ) / entriesPerRow ) > 1 ) ) { // More than 1 row or 1st row is full
float padding = std : : max < float > ( rowWidth - ( entriesPerRow * options . entryWidth ) , 0 ) / ( entriesPerRow + 1 ) ;
xChildGap = xPadding = padding ;
if ( o . entryWidthIsMinimum ) {
xPadding = padding / 2 ;
entryWidth = padding + options . entryWidth ;
xChildGap = 0 ;
}
else
xPadding = xChildGap = padding ;
}
2026-04-21 18:38:24 +03:00
2026-04-18 20:51:45 +03:00
opts . elementContent = [ & ] ( size_t rowIndex ) {
2026-04-19 10:03:57 +03:00
gui . new_id ( " grid row " , [ & ] {
CLAY_AUTO_ID ( {
. layout = {
2026-04-21 18:38:24 +03:00
. sizing = { . width = CLAY_SIZING_GROW ( 0 ) , . height = CLAY_SIZING_GROW ( 0 ) } ,
. padding = { . left = xPadding , . right = xPadding } ,
2026-04-28 20:55:30 +03:00
. childGap = xChildGap ,
2026-04-19 10:03:57 +03:00
. childAlignment = { . x = options . childAlignmentX }
}
} ) {
size_t startIndex = rowIndex * entriesPerRow ;
size_t endIndex = std : : min ( rowIndex * entriesPerRow + entriesPerRow , o . entryCount ) ;
for ( size_t i = startIndex ; i < endIndex ; i + + ) {
2026-04-19 13:37:16 +03:00
gui . new_id ( static_cast < int64_t > ( i - startIndex ) , [ & ] {
2026-04-19 10:03:57 +03:00
CLAY_AUTO_ID ( {
2026-04-21 18:38:24 +03:00
. layout = {
2026-04-28 20:55:30 +03:00
. sizing = { . width = CLAY_SIZING_FIXED ( entryWidth ) , . height = CLAY_SIZING_FIXED ( options . entryHeight ) } ,
2026-04-21 18:38:24 +03:00
}
2026-04-19 10:03:57 +03:00
} ) {
options . elementContent ( i ) ;
}
} ) ;
}
2026-04-18 20:51:45 +03:00
}
2026-04-19 10:03:57 +03:00
} ) ;
2026-04-18 20:51:45 +03:00
} ;
2026-04-19 10:03:57 +03:00
CLAY ( id , {
2026-04-21 18:38:24 +03:00
. layout = {
. sizing = { . width = CLAY_SIZING_GROW ( 0 ) , . height = CLAY_SIZING_GROW ( 0 ) }
}
2026-04-19 10:03:57 +03:00
} ) {
scroll_area_many_entries ( gui , " scroll many area " , opts ) ;
}
2026-04-18 20:51:45 +03:00
}
}