Merge branch 'text-shape' into develop

This commit is contained in:
Martín Lucas Golini
2025-11-02 17:58:13 -03:00
32 changed files with 1152 additions and 792 deletions

View File

@@ -204,7 +204,7 @@
},
"run": [
{
"args": "",
"args": "--text-shaper",
"command": "${project_root}/bin/ecode-debug",
"name": "ecode-debug",
"working_dir": "${project_root}/bin"

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -0,0 +1 @@
اسکم شاخ و دم نداره همین که کاربر شبکه خودت. کسی که رو شبکه تو فی داده سالها زحمت کشیده رو نادیده میگیری و به کاربر یه شبکه دیگه توکن سنگین میدی میشه اسکم علنی. باید کاری باهاش کنیم که مثل استارک به غلط کردن بیافته اره تو endgame هستی اخر اسکمرایی

View File

@@ -0,0 +1 @@
مَرْحَبًا بِالْعَالَم

View File

@@ -1 +1,24 @@
اسکم شاخ و دم نداره همین که کاربر شبکه خودت. کسی که رو شبکه تو فی داده سالها زحمت کشیده رو نادیده میگیری و به کاربر یه شبکه دیگه توکن سنگین میدی میشه اسکم علنی. باید کاری باهاش کنیم که مثل استارک به غلط کردن بیافته اره تو endgame هستی اخر اسکمرایی
Hello: مرحبا
Good morning: صباح الخير
Good night: تصبح على خير
Thank you: شكراً
You're welcome: عفواً
Yes / No: نعم / لا
Please: من فضلك
Excuse me / Sorry: عفواً / آسف
How are you?: كيف حالك؟
I'm fine. And you?: أنا بخير. وأنت؟
What's your name?: ما اسمك؟
My name is...: اسمي...
Nice to meet you: تشرفت بلقائك
Where are you from?: من أين أنت؟
I'm from...: أنا من...
Do you speak English?: هل تتحدث الإنجليزية؟
I don't understand: لا أفهم
Please speak more slowly: من فضلك تكلم ببطء أكثر
Please write it down: من فضلك اكتبه
How much is this?: كم سعره؟
Where is the bathroom?: أين الحمام؟
Help!: المساعدة!
Stop!: توقف!
Call the police!: اتصل بالشرطة!

View File

@@ -1,24 +1,24 @@
Hello: হ্যালো / নমস্কার
Good morning: সুপ্রভাত
Good night: শুভ রাত্রি
Thank you: ধন্যবাদ
You're welcome: আপনি স্বাগত জানাই
Yes / No: হ্যাঁ / না
Please: অনুগ্রহ করে
Excuse me / Sorry: মাফ করবেন / দুঃখিত
How are you?: আপনি কেমন আছেন?
I'm fine. And you?: আমি ভালো আছি। এবং আপনি?
What's your name?: আপনার নাম কি?
My name is...: আমার নাম...
Nice to meet you: আপনার সাথে দেখা করে খুশি
Where are you from?: আপনি কোথা থেকে এসেছেন?
I'm from...: আমি ... থেকে এসেছি।
Do you speak English?: আপনি কি ইংরেজি বলতে পারেন?
I don't understand: আমি বুঝতে পারছি না।
Please speak more slowly: অনুগ্রহ করে ধীরে বলুন।
Please write it down: অনুগ্রহ করে এটি লিখে দিন।
How much is this?: এটার দাম কত?
Where is the bathroom?: বাথরুম কোথায়?
Help!: বাঁচাও!
Stop!: থামুন!
Call the police!: পুলিশ ডাকুন!
Hello: হ্যালো / নমস্কার
Good morning: সুপ্রভাত
Good night: শুভ রাত্রি
Thank you: ধন্যবাদ
You're welcome: আপনি স্বাগত জানাই
Yes / No: হ্যাঁ / না
Please: অনুগ্রহ করে
Excuse me / Sorry: মাফ করবেন / দুঃখিত
How are you?: আপনি কেমন আছেন?
I'm fine. And you?: আমি ভালো আছি। এবং আপনি?
What's your name?: আপনার নাম কি?
My name is...: আমার নাম...
Nice to meet you: আপনার সাথে দেখা করে খুশি
Where are you from?: আপনি কোথা থেকে এসেছেন?
I'm from...: আমি ... থেকে এসেছি।
Do you speak English?: আপনি কি ইংরেজি বলতে পারেন?
I don't understand: আমি বুঝতে পারছি না।
Please speak more slowly: অনুগ্রহ করে ধীরে বলুন।
Please write it down: অনুগ্রহ করে এটি লিখে দিন।
How much is this?: এটার দাম কত?
Where is the bathroom?: বাথরুম কোথায়?
Help!: বাঁচাও!
Stop!: থামুন!
Call the police!: পুলিশ ডাকুন!

View File

@@ -154,6 +154,7 @@ class EE_API FontTrueType : public Font {
protected:
friend class Text;
friend class TextLayouter;
explicit FontTrueType( const std::string& FontName );

View File

@@ -10,6 +10,8 @@
namespace EE { namespace Graphics {
class FontTrueType;
enum class CharacterAlignment : Uint32 { Left = 0, Center = 1, Right = 2 };
struct WhitespaceDisplayConfig {
@@ -20,9 +22,76 @@ struct WhitespaceDisplayConfig {
std::optional<Float> tabOffset;
};
struct ShapedGlyph {
FontTrueType* font{ nullptr };
Uint32 glyphIndex{ 0 };
Uint32 stringIndex{ 0 };
Vector2f position;
};
struct TextLayout {
std::vector<ShapedGlyph> shapedGlyphs;
std::vector<Float> linesWidth;
Sizef size;
};
class EE_API TextLayouter {
public:
static TextLayout layout( const String& string, Font* font, const Uint32& fontSize,
const Uint32& style, const Uint32& tabWidth = 4,
const Float& outlineThickness = 0.f,
std::optional<Float> tabOffset = {}, Uint32 textDrawHints = 0 );
static TextLayout layout( const String::View& string, Font* font, const Uint32& fontSize,
const Uint32& style, const Uint32& tabWidth = 4,
const Float& outlineThickness = 0.f,
std::optional<Float> tabOffset = {}, Uint32 textDrawHints = 0 );
protected:
template <typename StringType>
static TextLayout layout( const StringType& string, Font* font, const Uint32& fontSize,
const Uint32& style, const Uint32& tabWidth = 4,
const Float& outlineThickness = 0.f,
std::optional<Float> tabOffset = {}, Uint32 textDrawHints = 0 );
};
// helper class that divides the string into lines and font runs.
class EE_API TextShapeRun {
public:
TextShapeRun( String::View str, FontTrueType* font, Uint32 characterSize, Uint32 style,
Float outlineThickness );
String::View curRun() const;
bool hasNext() const;
std::size_t pos() const;
void next();
bool runIsNewLine() const;
FontTrueType* font();
protected:
void findNextEnd();
String::View mString;
std::size_t mIndex{ 0 };
std::size_t mLen{ 0 };
Font* mFont{ nullptr };
Uint32 mCharacterSize;
Uint32 mStyle;
Float mOutlineThickness;
Font* mCurFont{ nullptr };
Font* mStartFont{ nullptr };
bool mIsNewLine{ false };
};
class EE_API Text {
public:
static bool TextShaperEnabled;
static bool TextShaperOptimizations;
static Uint32 GlobalInvalidationId;
enum Style {
@@ -98,14 +167,16 @@ class EE_API Text {
const Uint32& fontSize, const String& string,
const Uint32& style, const Uint32& tabWidth = 4,
const Float& outlineThickness = 0.f,
std::optional<Float> tabOffset = {} );
std::optional<Float> tabOffset = {},
Uint32 textDrawHints = 0 );
static Vector2f findCharacterPos( std::size_t index, Font* font, const Uint32& fontSize,
const String& string, const Uint32& style,
const Uint32& tabWidth = 4,
const Float& outlineThickness = 0.f,
std::optional<Float> tabOffset = {},
bool allowNewLine = true );
bool allowNewLine = true,
Uint32 textDrawHints = 0 );
static std::size_t findLastCharPosWithinLength( Font* font, const Uint32& fontSize,
const String& string, Float maxWidth,

View File

@@ -79,6 +79,8 @@ template <typename T> class tRECT {
T getHeight() const;
void normalize();
tRECT<T> ceil() const;
tRECT<T> floor() const;
@@ -265,6 +267,11 @@ template <typename T> tSize<T> tRECT<T>::getSize() const {
return tSize<T>( eeabs( Right - Left ), eeabs( Bottom - Top ) );
}
template <typename T> void tRECT<T>::normalize() {
if ( Left > Right ) std::swap( Left, Right );
if ( Top > Bottom ) std::swap( Top, Bottom );
}
template <typename T> T tRECT<T>::getWidth() const {
return eeabs( Right - Left );
}

View File

@@ -540,11 +540,13 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
size_t characterWidth( const String& str ) const;
Float getTextWidth( const String& text, std::optional<Float> tabOffset = {} ) const;
Float getTextWidth( const String& text, std::optional<Float> tabOffset = {},
Uint32 textHints = 0 ) const;
size_t characterWidth( const String::View& str ) const;
Float getTextWidth( const String::View& text, std::optional<Float> tabOffset ) const;
Float getTextWidth( const String::View& text, std::optional<Float> tabOffset,
Uint32 textHints = 0 ) const;
Float getLineHeight() const;
@@ -1131,13 +1133,13 @@ class EE_API UICodeEditor : public UIWidget, public TextDocument::Client {
template <typename StringType>
Float getTextWidth( const StringType& text, bool fromMonospaceLine,
std::optional<Float> tabOffset ) const;
std::optional<Float> tabOffset, Uint32 textHints = 0 ) const;
Float getTextWidth( const String& text, bool fromMonospaceLine,
std::optional<Float> tabOffset ) const;
Float getTextWidth( const String& text, bool fromMonospaceLine, std::optional<Float> tabOffset,
Uint32 textHints = 0 ) const;
Float getTextWidth( const String::View& text, bool fromMonospaceLine,
std::optional<Float> tabOffset ) const;
std::optional<Float> tabOffset, Uint32 textHints = 0 ) const;
void updateIMELocation();

View File

@@ -1290,11 +1290,17 @@ bool FontTrueType::setCurrentSize( unsigned int characterSize ) const {
}
} else if ( characterSize != currentSize &&
( result = FT_Set_Pixel_Sizes( face, 0, it->second ) ) == FT_Err_Ok ) {
#ifdef EE_TEXT_SHAPER_ENABLED
hb_ft_font_changed( (hb_font_t*)mHBFont );
#endif
return true;
}
}
}
#ifdef EE_TEXT_SHAPER_ENABLED
hb_ft_font_changed( (hb_font_t*)mHBFont );
#endif
return result == FT_Err_Ok;
} else {
return true;

File diff suppressed because it is too large Load Diff

View File

@@ -2080,7 +2080,8 @@ Float UICodeEditor::getLineWidth( const Int64& docLine ) {
auto len =
i + 1 < vline.visualLines.size() ? vline.visualLines[i + 1].column() : line.size();
auto vlineStr = line.view().substr( pos, len - pos );
auto curWidth = getTextWidth( vlineStr, isMonospaceLine );
auto curWidth =
getTextWidth( vlineStr, isMonospaceLine, {}, mDoc->line( docLine ).getTextHints() );
width = eemax( width, curWidth );
}
@@ -2096,13 +2097,15 @@ Float UICodeEditor::getLineWidth( const Int64& docLine ) {
auto found = mLinesWidthCache.find( docLine );
if ( found != mLinesWidthCache.end() && line.getHash() == found->second.first )
return found->second.second;
Float width = getTextWidth( line.getText(), {}, mTabStops ? 0 : std::optional<Float>{} );
Float width = getTextWidth( line.getText(), {}, mTabStops ? 0 : std::optional<Float>{},
line.getTextHints() );
mLinesWidthCache[docLine] = { line.getHash(), width };
return width;
}
return getTextWidth( mDoc->line( docLine ).getText(), isMonospaceLine,
mTabStops ? 0 : std::optional<Float>{} );
mTabStops ? 0 : std::optional<Float>{},
mDoc->line( docLine ).getTextHints() );
}
void UICodeEditor::updateScrollBar() {
@@ -2530,12 +2533,12 @@ Vector2d UICodeEditor::getTextPositionOffset( const TextPosition& position,
const auto& line = mDoc->line( position.line() ).getText();
auto partialLine =
line.view().substr( info.range.start().column(), info.range.end().column() );
Float x =
Text::findCharacterPos( position.column() - info.range.start().column(), mFont,
getCharacterSize(), partialLine, mFontStyleConfig.Style,
mTabWidth, mFontStyleConfig.OutlineThickness,
mTabStops ? 0 : std::optional<Float>(), false )
.x;
Float x = Text::findCharacterPos(
position.column() - info.range.start().column(), mFont,
getCharacterSize(), partialLine, mFontStyleConfig.Style, mTabWidth,
mFontStyleConfig.OutlineThickness, mTabStops ? 0 : std::optional<Float>(),
false, mDoc->line( position.line() ).getTextHints() )
.x;
if ( visualizeNewLine && allowVisualLineEnd &&
position.column() == (Int64)mDoc->line( position.line() ).getText().size() - 1 )
x += getGlyphWidth();
@@ -2567,7 +2570,8 @@ Vector2d UICodeEditor::getTextPositionOffset( const TextPosition& position,
Text::findCharacterPos(
isLastChar ? position.column() - 1 : position.column(), mFont, getCharacterSize(),
mDoc->line( position.line() ).getText(), mFontStyleConfig.Style, mTabWidth,
mFontStyleConfig.OutlineThickness, mTabStops ? 0 : std::optional<Float>(), false )
mFontStyleConfig.OutlineThickness, mTabStops ? 0 : std::optional<Float>(), false,
mDoc->line( position.line() ).getTextHints() )
.x;
if ( visualizeNewLine && isLastChar )
x += getGlyphWidth();
@@ -2600,34 +2604,36 @@ size_t UICodeEditor::characterWidth( const String& str ) const {
return characterWidth<String>( str );
}
Float UICodeEditor::getTextWidth( const String& text, std::optional<Float> tabOffset ) const {
return getTextWidth<String>( text, false, tabOffset );
Float UICodeEditor::getTextWidth( const String& text, std::optional<Float> tabOffset,
Uint32 textHints ) const {
return getTextWidth<String>( text, false, tabOffset, textHints );
}
size_t UICodeEditor::characterWidth( const String::View& str ) const {
return characterWidth<String::View>( str );
}
Float UICodeEditor::getTextWidth( const String::View& text, std::optional<Float> tabOffset ) const {
return getTextWidth<String::View>( text, false, tabOffset );
Float UICodeEditor::getTextWidth( const String::View& text, std::optional<Float> tabOffset,
Uint32 textHints ) const {
return getTextWidth<String::View>( text, false, tabOffset, textHints );
}
Float UICodeEditor::getTextWidth( const String& text, bool fromMonospaceLine,
std::optional<Float> tabOffset ) const {
return getTextWidth<String>( text, fromMonospaceLine, tabOffset );
std::optional<Float> tabOffset, Uint32 textHints ) const {
return getTextWidth<String>( text, fromMonospaceLine, tabOffset, textHints );
}
Float UICodeEditor::getTextWidth( const String::View& text, bool fromMonospaceLine,
std::optional<Float> tabOffset ) const {
return getTextWidth<String::View>( text, fromMonospaceLine, tabOffset );
std::optional<Float> tabOffset, Uint32 textHints ) const {
return getTextWidth<String::View>( text, fromMonospaceLine, tabOffset, textHints );
}
template <typename StringType>
Float UICodeEditor::getTextWidth( const StringType& line, bool fromMonospaceLine,
std::optional<Float> tabOffset ) const {
std::optional<Float> tabOffset, Uint32 textHints ) const {
if ( !fromMonospaceLine && isNotMonospace() ) {
return Text::getTextWidth( mFont, getCharacterSize(), line, mFontStyleConfig.Style,
mTabWidth, 0.f, 0, tabOffset );
mTabWidth, 0.f, textHints, tabOffset );
}
Float glyphWidth = getGlyphWidth();
@@ -3204,7 +3210,8 @@ Int64 UICodeEditor::getColFromXOffset( VisibleIndex visibleIndex, const Float& x
Text::findCharacterFromPos( Vector2i( eemax( -xOffset + x, 0.f ), 0 ), true,
mFont, getCharacterSize(), line,
mFontStyleConfig.Style, mTabWidth, 0.f,
mTabStops ? 0 : std::optional<Float>() );
mTabStops ? 0 : std::optional<Float>(),
mDoc->line( pos.line() ).getTextHints() );
}
Int64 len = line.length();
@@ -3230,7 +3237,8 @@ Int64 UICodeEditor::getColFromXOffset( VisibleIndex visibleIndex, const Float& x
if ( !isMonospaceLine( pos.line() ) ) {
return Text::findCharacterFromPos(
Vector2i( x, 0 ), true, mFont, getCharacterSize(), mDoc->line( pos.line() ).getText(),
mFontStyleConfig.Style, mTabWidth, 0.f, mTabStops ? 0 : std::optional<Float>() );
mFontStyleConfig.Style, mTabWidth, 0.f, mTabStops ? 0 : std::optional<Float>(),
mDoc->line( pos.line() ).getTextHints() );
}
const String& line = mDoc->line( pos.line() ).getText();
@@ -4193,6 +4201,7 @@ std::vector<Rectf> UICodeEditor::getTextRangeRectangles(
}
}
selRect.Right = startScroll.x + endOffset.x;
selRect.normalize();
rects.push_back( selRect );
}
} else {
@@ -4232,6 +4241,7 @@ std::vector<Rectf> UICodeEditor::getTextRangeRectangles(
lh, false, visualizeNewLines )
.x;
}
selRect.normalize();
rects.push_back( selRect );
}
}
@@ -5365,7 +5375,8 @@ void UICodeEditor::setTabIndentAlignment( CharacterAlignment alignment ) {
}
bool UICodeEditor::isMonospaceLine( Int64 lineIndex ) const {
return mFont && ( mFont->isMonospace() ||
return mFont && ( ( mFont->isMonospace() &&
( !Text::TextShaperEnabled || mDoc->line( lineIndex ).isAscii() ) ) ||
( mFont->getType() == FontType::TTF &&
static_cast<FontTrueType*>( mFont )->isIdentifiedAsMonospace() &&
mDoc->line( lineIndex ).isAscii() ) );

View File

@@ -152,6 +152,42 @@ void mainLoop() {
}
EE_MAIN_FUNC int main( int, char*[] ) {
{
Text::TextShaperEnabled = false;
UIApplication app( WindowSettings( 1024, 650, "eepp - TextEdit", WindowStyle::Default,
WindowBackend::Default, 32, {}, 1, false, true ),
UIApplication::Settings( {}, 1.5f ) );
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
auto ll = UILinearLayout::NewVertical();
ll->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
auto editor = UICodeEditor::New();
editor->setShowLineNumber( false );
editor->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
editor->setParent( ll );
// editor->setFontSize( PixelDensity::dpToPx( 32 ) );
/* FontManager::instance()->addFallbackFont(
FontTrueType::New( "arabic", "unit_tests/assets/fonts/NotoNaskhArabic-Regular.ttf" ) ); */
FontManager::instance()->addFallbackFont( FontTrueType::New(
"NotoSerifBengali-Regular", "unit_tests/assets/fonts/NotoSansBengali-Regular.ttf" ) );
// editor->setLineWrapMode( LineWrapMode::Word );
// editor->setFont( FontManager::instance()->getByName( "monospace" ) );
// editor->loadFromFile( "unit_tests/assets/textfiles/test-arabic-simple.uext" );
editor->loadFromFile( "unit_tests/assets/textfiles/test-arabic.uext" );
// editor->loadFromFile( "unit_tests/assets/textfiles/test-bengali.uext" );
// editor->loadFromFile( "unit_tests/assets/textfiles/test-flags.uext" );
// editor->loadFromFile( "unit_tests/assets/textformat/english.utf8.lf.nobom.txt" );
// editor->getDocument().textInput( "اسمي..." );
// editor->getDocument().textInput( " হ্যাঁ " );
editor->setFont( app.getUI()->getUIThemeManager()->getDefaultFont() );
editor->on( Event::KeyUp, [&]( const Event* event ) {
if ( event->asKeyEvent()->getKeyCode() == KEY_F1 ){
Text::TextShaperEnabled = !Text::TextShaperEnabled;
app.getUI()->getRoot()->invalidateDraw();
}
} );
return app.run();
}
win = Engine::instance()->createWindow( WindowSettings( 1366, 768, "eepp - UI Perf Test" ),
ContextSettings( false ) );
@@ -199,50 +235,50 @@ EE_MAIN_FUNC int main( int, char*[] ) {
->setDefaultFont( font )
->add( theme );
/*
auto* vlay = UILinearLayout::NewVertical();
vlay->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
/*
auto* vlay = UILinearLayout::NewVertical();
vlay->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
Clock clock;
auto model = FileSystemModel::New( "." ); // std::make_shared<TestModel>();
// UITreeView* view = UITreeView::New();
UITableView* view = UITableView::New();
// view->setExpanderIconSize( PixelDensity::dpToPx( 20 ) );
view->setId( "treeview" );
view->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
view->setParent( vlay );
view->setModel( SortingProxyModel::New( model ) );
Log::notice( "Total time: %.2fms", clock.getElapsedTime().asMilliseconds() );
*/
Clock clock;
auto model = FileSystemModel::New( "." ); // std::make_shared<TestModel>();
// UITreeView* view = UITreeView::New();
UITableView* view = UITableView::New();
// view->setExpanderIconSize( PixelDensity::dpToPx( 20 ) );
view->setId( "treeview" );
view->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
view->setParent( vlay );
view->setModel( SortingProxyModel::New( model ) );
Log::notice( "Total time: %.2fms", clock.getElapsedTime().asMilliseconds() );
*/
/* ListBox test */
/*
std::vector<String> strings;
for ( size_t i = 0; i < 10000; i++ )
strings.emplace_back( String::format(
"This is a very long string number %ld. Cover the full width of the listbox.",
i ) );
auto* lbox = UIListBox::New();
std::cout << "Time New: " << clock.getElapsedTime().asMilliseconds() << " ms" << std::endl;
lbox->setParent( vlay );
std::cout << "Time setParent: " << clock.getElapsedTime().asMilliseconds() << " ms"
<< std::endl;
lbox->setLayoutMargin( Rectf( 4, 4, 4, 4 ) );
std::cout << "Time setLayoutMargin: " << clock.getElapsedTime().asMilliseconds() << " ms"
<< std::endl;
lbox->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
std::cout << "Time setLayoutSizePolicy: " << clock.getElapsedTime().asMilliseconds()
<< " ms" << std::endl;
for ( size_t i = 0; i < 10; i++ )
lbox->addListBoxItem( String::format(
"This is a very long string number %ld. Cover the full width of the listbox.",
i ) );
std::cout << "Time addListBoxItem: " << clock.getElapsedTime().asMilliseconds() << " ms"
<< std::endl;
lbox->addListBoxItems( strings );
std::cout << "Time addListBoxItems: " << clock.getElapsedTime().asMilliseconds() << " ms"
<< std::endl;
*/
/*
std::vector<String> strings;
for ( size_t i = 0; i < 10000; i++ )
strings.emplace_back( String::format(
"This is a very long string number %ld. Cover the full width of the
listbox.", i ) ); auto* lbox = UIListBox::New(); std::cout << "Time New: " <<
clock.getElapsedTime().asMilliseconds() << " ms" << std::endl; lbox->setParent( vlay );
std::cout << "Time setParent: " << clock.getElapsedTime().asMilliseconds() << " ms"
<< std::endl;
lbox->setLayoutMargin( Rectf( 4, 4, 4, 4 ) );
std::cout << "Time setLayoutMargin: " << clock.getElapsedTime().asMilliseconds() <<
" ms"
<< std::endl;
lbox->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
std::cout << "Time setLayoutSizePolicy: " << clock.getElapsedTime().asMilliseconds()
<< " ms" << std::endl;
for ( size_t i = 0; i < 10; i++ )
lbox->addListBoxItem( String::format(
"This is a very long string number %ld. Cover the full width of the
listbox.", i ) ); std::cout << "Time addListBoxItem: " <<
clock.getElapsedTime().asMilliseconds() << " ms"
<< std::endl;
lbox->addListBoxItems( strings );
std::cout << "Time addListBoxItems: " << clock.getElapsedTime().asMilliseconds() <<
" ms"
<< std::endl;
*/
Clock total;
/* Create Widget test */
@@ -277,7 +313,8 @@ EE_MAIN_FUNC int main( int, char*[] ) {
but->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
but->setParent( parent )->clipEnable();
}
std::cout << "Time 10k UIPushButton total: " << total.getElapsedTime().toString() << std::endl;
std::cout << "Time 10k UIPushButton total: " << total.getElapsedTime().toString()
<< std::endl;
// uiSceneNode->getRoot()->closeAllChildren();
total.restart();
@@ -285,115 +322,117 @@ EE_MAIN_FUNC int main( int, char*[] ) {
std::cout << "SceneManager::instance()->update(): " << total.getElapsedTime().toString()
<< std::endl;
/*
auto* main = UIRelativeLayout::New();
main->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
auto* sv = UIScrollView::New();
sv->setParent( main );
sv->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
sv->setPixelsSize( win->getSize().asFloat() );
auto* vlay = UILinearLayout::NewVertical();
vlay->setParent( sv );
vlay->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
/*
auto* main = UIRelativeLayout::New();
main->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
auto* sv = UIScrollView::New();
sv->setParent( main );
sv->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
sv->setPixelsSize( win->getSize().asFloat() );
auto* vlay = UILinearLayout::NewVertical();
vlay->setParent( sv );
vlay->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
total.restart();
for ( size_t i = 0; i < 100000; i++ ) {
auto* widget = UIWidget::New();
widget->setParent( vlay );
widget->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed );
widget->setSize( Sizef( 0, 4 ) );
Colorf col;
col.hsv.h = Math::randf( 0, 360 );
col.hsv.s = 1;
col.hsv.v = 1;
col.hsv.a = 1;
widget->setBackgroundColor( Color::fromHsv( col ) );
}
std::cout << "Time UIWidget total: " << total.getElapsedTime().asMilliseconds() << " ms"
<< std::endl;
*/
/*
UIWindow* wind = UIWindow::New();
wind->setSize( 500, 500 );
wind->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_RESIZEABLE | UI_WIN_MAXIMIZE_BUTTON );
total.restart();
for ( size_t i = 0; i < 100000; i++ ) {
auto* widget = UIWidget::New();
widget->setParent( vlay );
widget->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed );
widget->setSize( Sizef( 0, 4 ) );
Colorf col;
col.hsv.h = Math::randf( 0, 360 );
col.hsv.s = 1;
col.hsv.v = 1;
col.hsv.a = 1;
widget->setBackgroundColor( Color::fromHsv( col ) );
}
std::cout << "Time UIWidget total: " << total.getElapsedTime().asMilliseconds() << "
ms"
<< std::endl;
*/
/*
UIWindow* wind = UIWindow::New();
wind->setSize( 500, 500 );
wind->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_RESIZEABLE |
UI_WIN_MAXIMIZE_BUTTON );
UILinearLayout* layWin = UILinearLayout::NewVertical();
layWin->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
layWin->setParent( wind );
UILinearLayout* layWin = UILinearLayout::NewVertical();
layWin->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
layWin->setParent( wind );
UILinearLayout* layPar = UILinearLayout::NewHorizontal();
layPar->setParent( layWin );
layPar->setLayoutMargin( Rectf( 10, 10, 10, 10 ) );
layPar->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
layPar->setLayoutGravity( UI_VALIGN_CENTER | UI_HALIGN_CENTER );
layPar->setBackgroundColor( 0x999999FF );
UILinearLayout* layPar = UILinearLayout::NewHorizontal();
layPar->setParent( layWin );
layPar->setLayoutMargin( Rectf( 10, 10, 10, 10 ) );
layPar->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
layPar->setLayoutGravity( UI_VALIGN_CENTER | UI_HALIGN_CENTER );
layPar->setBackgroundColor( 0x999999FF );
UILinearLayout* lay = UILinearLayout::NewVertical();
lay->setLayoutGravity( UI_HALIGN_CENTER | UI_VALIGN_CENTER );
lay->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
lay->setBackgroundColor( 0x333333FF );
lay->setLayoutWeight( 0.7f );
UILinearLayout* lay = UILinearLayout::NewVertical();
lay->setLayoutGravity( UI_HALIGN_CENTER | UI_VALIGN_CENTER );
lay->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent );
lay->setBackgroundColor( 0x333333FF );
lay->setLayoutWeight( 0.7f );
UITextView::New()
->setText( "Text on test 1" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent )
->setParent( lay );
UITextView::New()
->setText( "Text on test 2" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UICheckBox::New()
->setText( "Checkbox" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UITextView::New()
->setText( "Text on test 3" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UITextView::New()
->setText( "Text on test 4" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UITextInput::New()
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UITextView::New()
->setText( "Text on test 1" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::WrapContent )
->setParent( lay );
UITextView::New()
->setText( "Text on test 2" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UICheckBox::New()
->setText( "Checkbox" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UITextView::New()
->setText( "Text on test 3" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UITextView::New()
->setText( "Text on test 4" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UITextInput::New()
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( lay );
UILinearLayout* lay2 = UILinearLayout::NewVertical();
lay2->setId( "hardlay" );
lay2->setLayoutGravity( UI_HALIGN_CENTER | UI_VALIGN_CENTER );
lay2->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::WrapContent );
lay2->setBackgroundColor( Color::Black );
lay2->setLayoutWeight( 0.3f );
UILinearLayout* lay2 = UILinearLayout::NewVertical();
lay2->setId( "hardlay" );
lay2->setLayoutGravity( UI_HALIGN_CENTER | UI_VALIGN_CENTER );
lay2->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::WrapContent );
lay2->setBackgroundColor( Color::Black );
lay2->setLayoutWeight( 0.3f );
UIPushButton::New()
->setText( "PushButton" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setLayoutGravity( UI_VALIGN_CENTER )
->setParent( lay2 );
UIListBox* lbox = UIListBox::New();
lbox->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed )
->setSize( 0, 105 )
->setParent( lay2 );
lbox->addListBoxItems( { "This", "is", "a", "ListBox" } );
lay2->setParent( layPar );
lay->setParent( layPar );
UIPushButton::New()
->setText( "PushButton" )
->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setLayoutGravity( UI_VALIGN_CENTER )
->setParent( lay2 );
UIListBox* lbox = UIListBox::New();
lbox->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::Fixed )
->setSize( 0, 105 )
->setParent( lay2 );
lbox->addListBoxItems( { "This", "is", "a", "ListBox" } );
lay2->setParent( layPar );
lay->setParent( layPar );
UIDropDownList* drop = UIDropDownList::New();
drop->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( layWin );
drop->getListBox()->addListBoxItems( { "Car", "Bus", "Plane", "Submarine" } );
drop->getListBox()->setSelected( 0 );
wind->show();
*/
UIDropDownList* drop = UIDropDownList::New();
drop->setLayoutMargin( Rectf( 10, 10, 10, 10 ) )
->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
->setParent( layWin );
drop->getListBox()->addListBoxItems( { "Car", "Bus", "Plane", "Submarine" } );
drop->getListBox()->setSelected( 0 );
wind->show();
*/
win->runMainLoop( &mainLoop );
}

View File

@@ -1,7 +1,7 @@
#include "eepp/ui/uithememanager.hpp"
#include "utest.hpp"
#include <eepp/graphics/fontbmfont.hpp>
#include <eepp/graphics/fontfamily.hpp>
#include <eepp/graphics/fontmanager.hpp>
#include <eepp/graphics/fontsprite.hpp>
#include <eepp/graphics/fonttruetype.hpp>
@@ -17,6 +17,7 @@
#include <eepp/ui/uiscenenode.hpp>
#include <eepp/ui/uitextedit.hpp>
#include <eepp/ui/uitextview.hpp>
#include <eepp/ui/uithememanager.hpp>
#include <eepp/window/engine.hpp>
#include <iostream>
@@ -52,7 +53,10 @@ static void compareImages( utest_state_s& utest_state, int* utest_result, EE::Wi
EXPECT_TRUE( result.areSame() );
if ( !result.areSame() ) {
auto saveExt( Image::saveTypeToExtension( saveType ) );
std::string withTextShaper = Text::TextShaperEnabled ? "_text_shape" : "";
std::string withTextShaper =
Text::TextShaperEnabled
? ( Text::TextShaperOptimizations ? "_text_shape_no_opt" : "_text_shape" )
: "";
std::cerr << "Test FAILED: " << result.numDifferentPixels << " pixels differ." << std::endl;
std::cerr << "Maximum perceptual difference (Delta E): " << result.maxDeltaE << std::endl;
if ( !FileSystem::fileExists( "output" ) )
@@ -183,6 +187,10 @@ UTEST( FontRendering, fontsTest ) {
{
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest();
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
}
@@ -211,6 +219,10 @@ UTEST( FontRendering, editorTest ) {
{
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest();
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
}
@@ -236,6 +248,10 @@ UTEST( FontRendering, textEditTest ) {
{
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest();
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
}
@@ -248,7 +264,7 @@ UTEST( FontRendering, tabsTest ) {
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
auto* editor = UICodeEditor::New();
editor->setPixelsSize( app.getUI()->getPixelsSize() );
editor->loadFromFile( "assets/fontrendering/tabs_test.txt" );
editor->loadFromFile( "assets/textfiles/test-tabs.txt" );
SceneManager::instance()->update();
SceneManager::instance()->draw();
compareImages( utest_state, utest_result, app.getWindow(),
@@ -262,6 +278,10 @@ UTEST( FontRendering, tabsTest ) {
{
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest();
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
}
@@ -275,7 +295,7 @@ UTEST( FontRendering, tabStopTest ) {
auto* editor = UICodeEditor::New();
editor->setTabStops( true );
editor->setPixelsSize( app.getUI()->getPixelsSize() );
editor->loadFromFile( "assets/fontrendering/tabs_test.txt" );
editor->loadFromFile( "assets/textfiles/test-tabs.txt" );
SceneManager::instance()->update();
SceneManager::instance()->draw();
compareImages( utest_state, utest_result, app.getWindow(),
@@ -289,6 +309,10 @@ UTEST( FontRendering, tabStopTest ) {
{
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest();
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
}
@@ -301,7 +325,7 @@ UTEST( FontRendering, tabsTextEditTest ) {
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
auto* editor = UITextEdit::New();
editor->setPixelsSize( app.getUI()->getPixelsSize() );
editor->loadFromFile( "assets/fontrendering/tabs_test.txt" );
editor->loadFromFile( "assets/textfiles/test-tabs.txt" );
SceneManager::instance()->update();
SceneManager::instance()->draw();
compareImages( utest_state, utest_result, app.getWindow(), "eepp-text-edit-tabs-test" );
@@ -314,6 +338,10 @@ UTEST( FontRendering, tabsTextEditTest ) {
{
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest();
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
}
@@ -327,7 +355,7 @@ UTEST( FontRendering, tabStopTextEditTest ) {
auto* editor = UITextEdit::New();
editor->setTabStops( true );
editor->setPixelsSize( app.getUI()->getPixelsSize() );
editor->loadFromFile( "assets/fontrendering/tabs_test.txt" );
editor->loadFromFile( "assets/textfiles/test-tabs.txt" );
SceneManager::instance()->update();
SceneManager::instance()->draw();
compareImages( utest_state, utest_result, app.getWindow(), "eepp-text-edit-tab-stop-test" );
@@ -340,6 +368,10 @@ UTEST( FontRendering, tabStopTextEditTest ) {
{
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest();
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
}
@@ -367,6 +399,10 @@ UTEST( FontRendering, textViewTest ) {
{
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest();
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
}
@@ -377,8 +413,8 @@ UTEST( FontRendering, textEditBengaliTest ) {
WindowBackend::Default, 32, {}, 1, false, true ),
UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1.5f ) );
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
FontTrueType* bengaliFont = FontTrueType::New( "NotoSerifBengali-Regular",
"assets/fonts/NotoSerifBengali-Regular.ttf" );
FontTrueType* bengaliFont =
FontTrueType::New( "NotoSansBengali-Regular", "assets/fonts/NotoSansBengali-Regular.ttf" );
FontManager::instance()->addFallbackFont( bengaliFont );
UTEST_PRINT_STEP( "Text Shaper enabled" );
auto* editor = UITextEdit::New();
@@ -396,6 +432,8 @@ UTEST( FontRendering, textSizes ) {
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
Text::TextShaperEnabled = false;
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
@@ -417,6 +455,12 @@ UTEST( FontRendering, textSizes ) {
EXPECT_EQ( 96, size.getHeight() );
EXPECT_EQ( 445, Text::getTextWidth( txt, config ) );
Vector2i topPos{ 120, 0 };
EXPECT_EQ( 19, Text::findCharacterFromPos( topPos, true, config.Font, config.CharacterSize,
txt, 0 ) );
EXPECT_EQ( 19, Text::findCharacterFromPos( topPos, false, config.Font, config.CharacterSize,
txt, 0 ) );
Vector2i startPos{ 120, 7 };
EXPECT_EQ( 19, Text::findCharacterFromPos( startPos, true, config.Font,
config.CharacterSize, txt, 0 ) );
@@ -427,7 +471,7 @@ UTEST( FontRendering, textSizes ) {
EXPECT_EQ( 242, Text::findCharacterFromPos( middlePos, true, config.Font,
config.CharacterSize, txt, 0 ) );
EXPECT_EQ( 242, Text::findCharacterFromPos( middlePos, false, config.Font,
config.CharacterSize, txt, 0 ) );
config.CharacterSize, txt, 0 ) );
Vector2i endPos{ 120, 103 };
EXPECT_EQ( 395, Text::findCharacterFromPos( endPos, true, config.Font, config.CharacterSize,
@@ -436,6 +480,8 @@ UTEST( FontRendering, textSizes ) {
txt, 0 ) );
EXPECT_EQ( 18ul, Text::findLastCharPosWithinLength( txt, 120, config ) );
EXPECT_EQ( 446ul, Text::findLastCharPosWithinLength( txt, 1000, config ) );
Vector2f pos = Text::findCharacterPos( 19, config.Font, config.CharacterSize, txt, 0 );
EXPECT_EQ( 120, pos.x );
EXPECT_EQ( 0, pos.y );
@@ -467,5 +513,89 @@ UTEST( FontRendering, textSizes ) {
runTest();
}
UTEST_PRINT_STEP( "Text Shaper enabled w/o optimizations" );
{
BoolScopedOp op( Text::TextShaperEnabled, true );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest();
}
Engine::destroySingleton();
}
UTEST( FontRendering, textStyles ) {
auto win = Engine::instance()->createWindow(
WindowSettings( 1024, 230, "eepp - Text Styles", WindowStyle::Default,
WindowBackend::Default, 32, {}, 1, false, true ) );
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
Text::TextShaperEnabled = false;
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
FontFamily::loadFromRegular( font );
win->setClearColor( RGB( 255, 255, 255 ) );
FontStyleConfig config;
config.Font = font;
config.FontColor = Color::Black;
config.CharacterSize = 20;
config.OutlineColor = Color::Black;
config.ShadowColor = Color::lightgray;
String txt( "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\n"
"tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\n"
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\n"
"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\n"
"cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\n"
"proident, sunt in culpa qui officia deserunt mollit anim id est laborum." );
const auto runTest = [&]( std::string_view styleName, Uint32 textAlign ) {
win->clear();
Text text;
text.setStyleConfig( config );
text.setString( txt );
text.setAlign( textAlign );
text.draw( 32, 32 );
compareImages( utest_state, utest_result, win, "eepp-text-style-" + styleName );
};
const auto runTestSuite = [&]( Uint32 style, std::string_view styleName,
Uint32 textAlign = TEXT_ALIGN_LEFT ) {
config.Style = style;
UTEST_PRINT_STEP( styleName.data() );
UTEST_PRINT_STEP( " Text Shaper disabled" );
runTest( styleName, textAlign );
UTEST_PRINT_STEP( " Text Shaper enabled" );
BoolScopedOp op( Text::TextShaperEnabled, true );
runTest( styleName, textAlign );
UTEST_PRINT_STEP( " Text Shaper enabled w/o optimizations" );
BoolScopedOp op2( Text::TextShaperOptimizations, false );
runTest( styleName, textAlign );
};
runTestSuite( Text::Regular, "regular" );
runTestSuite( Text::Bold, "bold" );
runTestSuite( Text::Italic, "italic" );
runTestSuite( Text::Underlined, "underline" );
runTestSuite( Text::StrikeThrough, "strikethrough" );
runTestSuite( Text::Shadow, "shadow" );
config.FontColor = Color::White;
config.OutlineThickness = 1;
runTestSuite( Text::Regular, "outline" );
config.FontColor = Color::Black;
config.OutlineThickness = 0;
runTestSuite( Text::Regular, "regular-center", TEXT_ALIGN_CENTER );
runTestSuite( Text::Regular, "regular-right", TEXT_ALIGN_RIGHT );
runTestSuite( Text::Underlined, "underline-center", TEXT_ALIGN_CENTER );
runTestSuite( Text::Underlined, "underline-right", TEXT_ALIGN_RIGHT );
runTestSuite( Text::StrikeThrough, "strikethrough-center", TEXT_ALIGN_CENTER );
runTestSuite( Text::StrikeThrough, "strikethrough-right", TEXT_ALIGN_RIGHT );
Engine::destroySingleton();
}