2025-11-08 20:50:23 +03:00
# include "FontPicker.hpp"
# include "Helpers/ConvertVec.hpp"
# include <algorithm>
# include <modules/skparagraph/include/DartTypes.h>
# include <modules/skparagraph/include/ParagraphStyle.h>
# include <modules/skparagraph/src/ParagraphBuilderImpl.h>
# include <modules/skunicode/include/SkUnicode_icu.h>
# include <Helpers/Random.hpp>
bool GUIStuff : : FontPicker : : update ( UpdateInputData & io , std : : string * fontName , GUIManager * gui ) {
if ( sortedFontList . empty ( ) ) {
auto icu = SkUnicodes : : ICU : : Make ( ) ;
2025-11-15 17:03:14 +03:00
std : : set < std : : string > sortedFontSet ;
2025-11-16 10:42:01 +03:00
for ( int i = 0 ; i < io . fonts - > localFontMgr - > countFamilies ( ) ; i + + ) {
2025-11-08 20:50:23 +03:00
SkString familyNameSkString ;
2025-11-16 10:42:01 +03:00
io . fonts - > localFontMgr - > getFamilyName ( i , & familyNameSkString ) ;
2025-11-11 19:52:45 +03:00
if ( familyNameSkString . isEmpty ( ) )
continue ;
std : : string familyName ( familyNameSkString . c_str ( ) , familyNameSkString . size ( ) ) ;
2025-11-15 17:03:14 +03:00
sortedFontSet . emplace ( familyName ) ;
2025-11-11 19:52:45 +03:00
}
2025-11-16 10:42:01 +03:00
for ( int i = 0 ; i < io . fonts - > defaultFontMgr - > countFamilies ( ) ; i + + ) {
2025-11-11 19:52:45 +03:00
SkString familyNameSkString ;
2025-11-16 10:42:01 +03:00
io . fonts - > defaultFontMgr - > getFamilyName ( i , & familyNameSkString ) ;
2025-11-11 19:52:45 +03:00
if ( familyNameSkString . isEmpty ( ) )
continue ;
2025-11-08 20:50:23 +03:00
std : : string familyName ( familyNameSkString . c_str ( ) , familyNameSkString . size ( ) ) ;
2025-11-15 17:03:14 +03:00
sortedFontSet . emplace ( familyName ) ;
2025-11-08 20:50:23 +03:00
}
2025-11-15 17:03:14 +03:00
sortedFontList = std : : vector < std : : string > ( sortedFontSet . begin ( ) , sortedFontSet . end ( ) ) ;
sortedFontListLowercase = sortedFontList ;
for ( std : : string & s : sortedFontListLowercase )
std : : transform ( s . begin ( ) , s . end ( ) , s . begin ( ) , : : tolower ) ;
2025-11-08 20:50:23 +03:00
}
if ( ! fontName )
return false ;
bool fontChangedFromTextbox = false ;
bool fontChangedFromSelection = false ;
bool clickedOut = io . mouse . leftClick ;
const float ENTRY_HEIGHT = 25.0f ;
CLAY ( {
. layout = {
. sizing = { . width = CLAY_SIZING_FIXED ( 250 ) , . height = CLAY_SIZING_FIT ( 0 ) } ,
. childGap = 4
}
} ) {
fontChangedFromTextbox = gui - > input_text ( " Font textbox " , fontName , true , [ & ] ( SelectionHelper & s ) {
if ( s . selected ) {
dropdownOpen = true ;
clickedOut = false ;
}
} ) ;
auto it = std : : lower_bound ( sortedFontList . begin ( ) , sortedFontList . end ( ) , * fontName ) ;
size_t val = ( it ! = sortedFontList . end ( ) & & * it = = * fontName ) ? ( it - sortedFontList . begin ( ) ) : std : : numeric_limits < size_t > : : max ( ) ;
if ( val = = std : : numeric_limits < size_t > : : max ( ) ) {
std : : string lowerFamilyName = * fontName ;
std : : transform ( lowerFamilyName . begin ( ) , lowerFamilyName . end ( ) , lowerFamilyName . begin ( ) , : : tolower ) ;
auto itLower = std : : lower_bound ( sortedFontListLowercase . begin ( ) , sortedFontListLowercase . end ( ) , lowerFamilyName ) ;
2025-11-09 12:55:35 +03:00
val = ( itLower ! = sortedFontListLowercase . end ( ) & & * itLower = = lowerFamilyName ) ? ( itLower - sortedFontListLowercase . begin ( ) ) : std : : numeric_limits < size_t > : : max ( ) ;
2025-11-08 20:50:23 +03:00
if ( val ! = std : : numeric_limits < size_t > : : max ( ) )
* fontName = sortedFontList [ val ] ;
}
if ( gui - > svg_icon_button ( " Open font dropdown " , " data/icons/droparrow.svg " , dropdownOpen , GUIManager : : SMALL_BUTTON_SIZE ) ) {
dropdownOpen = ! dropdownOpen ;
clickedOut = false ;
}
if ( dropdownOpen ) {
CLAY ( {
. layout = {
. sizing = { . width = CLAY_SIZING_FIXED ( 250 ) , . height = CLAY_SIZING_FIT ( 0 , 300 ) } ,
} ,
. backgroundColor = convert_vec4 < Clay_Color > ( io . theme - > backColor1 ) ,
. cornerRadius = CLAY_CORNER_RADIUS ( 4 ) ,
. floating = {
. offset = {
. y = 2
} ,
. attachPoints = {
. element = CLAY_ATTACH_POINT_LEFT_TOP ,
. parent = CLAY_ATTACH_POINT_LEFT_BOTTOM
} ,
. attachTo = CLAY_ATTACH_TO_PARENT
} ,
. border = {
. color = convert_vec4 < Clay_Color > ( io . theme - > fillColor2 ) ,
. width = CLAY_BORDER_OUTSIDE ( 1 )
}
} ) {
gui - > obstructing_window ( ) ;
if ( Clay_Hovered ( ) )
clickedOut = false ;
gui - > scroll_bar_many_entries_area ( " Font Selector " , ENTRY_HEIGHT , sortedFontList . size ( ) , [ fontName , gui , & fontChangedFromSelection , & sortedFontList = sortedFontList , val , & io = io ] ( size_t i , bool listHovered ) {
bool selectedEntry = val = = i ;
skia : : textlayout : : ParagraphStyle pStyle ;
pStyle . setTextAlign ( skia : : textlayout : : TextAlign : : kLeft ) ;
pStyle . setTextHeightBehavior ( skia : : textlayout : : kDisableAll ) ;
skia : : textlayout : : StrutStyle strutStyle ;
strutStyle . setStrutEnabled ( true ) ;
strutStyle . setForceStrutHeight ( true ) ;
pStyle . setStrutStyle ( strutStyle ) ;
skia : : textlayout : : TextStyle tStyle ;
tStyle . setFontSize ( io . fontSize ) ;
tStyle . setFontFamilies ( { SkString { sortedFontList [ i ] . c_str ( ) } , SkString { " Roboto " } } ) ;
tStyle . setForegroundColor ( SkPaint { io . theme - > frontColor1 } ) ;
pStyle . setTextStyle ( tStyle ) ;
2025-11-16 10:42:01 +03:00
skia : : textlayout : : ParagraphBuilderImpl pBuilder ( pStyle , io . fonts - > collection , SkUnicodes : : ICU : : Make ( ) ) ;
2025-11-08 20:50:23 +03:00
tStyle . setFontStyle ( SkFontStyle : : Normal ( ) ) ;
pBuilder . pushStyle ( tStyle ) ;
pBuilder . addText ( sortedFontList [ i ] . c_str ( ) , sortedFontList [ i ] . size ( ) ) ;
auto p = pBuilder . Build ( ) ;
CLAY ( {
. layout = {
. sizing = { . width = CLAY_SIZING_FIXED ( 250 ) , . height = CLAY_SIZING_FIXED ( 25 ) } ,
. childGap = 1 ,
. childAlignment = { . x = CLAY_ALIGN_X_LEFT , . y = CLAY_ALIGN_Y_TOP } ,
. layoutDirection = CLAY_TOP_TO_BOTTOM
}
} ) {
SkColor4f entryColor ;
if ( selectedEntry )
entryColor = io . theme - > backColor2 ;
else if ( Clay_Hovered ( ) )
entryColor = io . theme - > backColor2 ;
else
entryColor = io . theme - > backColor1 ;
CLAY ( {
. layout = {
2025-11-15 14:05:05 +03:00
. sizing = { . width = CLAY_SIZING_GROW ( 0 ) , . height = CLAY_SIZING_FIXED ( 25 ) } ,
2025-11-08 20:50:23 +03:00
. padding = { . left = 2 , . right = 2 } ,
. childAlignment = { . x = CLAY_ALIGN_X_LEFT , . y = CLAY_ALIGN_Y_CENTER }
} ,
. backgroundColor = convert_vec4 < Clay_Color > ( entryColor )
} ) {
2025-11-15 14:05:05 +03:00
gui - > text_paragraph ( " font name " , std : : move ( p ) , 10000.0f ) ; // Setting width to numeric_limits::max will lead to multiplying it by any number greater than 1 to = infinity, which will cause issues
2025-11-08 20:50:23 +03:00
if ( io . mouse . leftClick & & Clay_Hovered ( ) ) {
* fontName = sortedFontList [ i ] ;
fontChangedFromSelection = true ;
}
}
}
} , [ ENTRY_HEIGHT , fontChangedFromTextbox , io = & io , val ] ( float scrollContentHeight , float containerHeight , float & scrollAmount ) {
if ( fontChangedFromTextbox & & ! io - > mouse . leftClick & & val ! = std : : numeric_limits < size_t > : : max ( ) )
scrollAmount = - static_cast < float > ( val ) * ENTRY_HEIGHT ;
} ) ;
}
}
}
if ( clickedOut )
dropdownOpen = false ;
return fontChangedFromSelection | fontChangedFromTextbox ;
}
void GUIStuff : : FontPicker : : clay_draw ( SkCanvas * canvas , UpdateInputData & io , Clay_RenderCommand * command ) {
}