mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Fix br element tag.
Fix gumbo dependency in ecode. Fix crash in StyleSheet::getStyleSheetStyleByAtRule. Plus some minor nits.
This commit is contained in:
@@ -162,10 +162,6 @@ markdownview a:hover {
|
||||
color: var(--font-highlight);
|
||||
}
|
||||
|
||||
br {
|
||||
layout-height: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
scale-type: fit-inside;
|
||||
layout-width: wrap_content;
|
||||
@@ -191,6 +187,10 @@ markdownview table > thead > tr > th {
|
||||
font-style: bold;
|
||||
}
|
||||
|
||||
markdownview CodeEditor {
|
||||
padding: 4dp;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding-left: 8dp;
|
||||
background-color: var(--list-back);
|
||||
|
||||
@@ -120,6 +120,7 @@ enum UINodeType {
|
||||
UI_TYPE_HTML_TABLE_CELL,
|
||||
UI_TYPE_DROPDOWNMODELLIST,
|
||||
UI_TYPE_DIFF_VIEW,
|
||||
UI_TYPE_BR,
|
||||
UI_TYPE_MODULES = 10000,
|
||||
UI_TYPE_TERMINAL = 10001,
|
||||
UI_TYPE_USER = 200000,
|
||||
|
||||
@@ -26,7 +26,7 @@ class EE_API UIRichText : public UILayout {
|
||||
|
||||
static UIRichText* NewH6() { return UIRichText::NewWithTag( "h6" ); };
|
||||
|
||||
static UIRichText* NewBr() { return UIRichText::NewWithTag( "br" ); };
|
||||
static UIRichText* NewBr();
|
||||
|
||||
static UIRichText* NewDiv() { return UIRichText::NewWithTag( "div" ); };
|
||||
|
||||
|
||||
@@ -1726,7 +1726,10 @@ solution "eepp"
|
||||
language "C++"
|
||||
files { "src/tools/ecode/**.cpp" }
|
||||
includedirs { "src/thirdparty/efsw/include", "src/thirdparty", "src/modules/eterm/include/", "src/modules/languages-syntax-highlighting/src" }
|
||||
links { "efsw-static", "eterm-static", "languages-syntax-highlighting-static", "libyaml-static", "gumbo-parser-static" }
|
||||
links { "efsw-static", "eterm-static", "languages-syntax-highlighting-static", "libyaml-static" }
|
||||
if os.is("windows") and is_vs() then
|
||||
links { "gumbo-parser-static" }
|
||||
end
|
||||
if not os.is("windows") and not os.is("haiku") then
|
||||
links { "pthread" }
|
||||
end
|
||||
|
||||
@@ -1605,12 +1605,13 @@ workspace "eepp"
|
||||
language "C++"
|
||||
files { "src/tools/ecode/**.cpp" }
|
||||
incdirs { "src/thirdparty/efsw/include", "src/thirdparty", "src/modules/eterm/include/", "src/modules/languages-syntax-highlighting/src" }
|
||||
links { "efsw-static", "eterm-static", "languages-syntax-highlighting-static", "libyaml-static", "gumbo-parser-static" }
|
||||
links { "efsw-static", "eterm-static", "languages-syntax-highlighting-static", "libyaml-static" }
|
||||
build_link_configuration( "ecode", false )
|
||||
filter { "system:windows", "action:not vs*" }
|
||||
buildoptions{ "-Wa,-mbig-obj" }
|
||||
linkoptions { "-Wl,--export-all-symbols" }
|
||||
filter { "system:windows", "action:vs*" }
|
||||
links { "gumbo-parser-static" }
|
||||
files { "bin/assets/icon/ecode.rc", "bin/assets/icon/ecode.ico" }
|
||||
vpaths { ['Resources/*'] = { "ecode.rc", "ecode.ico" } }
|
||||
filter { "system:windows", "action:not vs*", "architecture:x86" }
|
||||
|
||||
0
flake.lock → projects/nix/flake.lock
generated
0
flake.lock → projects/nix/flake.lock
generated
@@ -365,22 +365,18 @@ void StyleSheet::addMediaQueryList( MediaQueryList::ptr list ) {
|
||||
}
|
||||
}
|
||||
|
||||
StyleSheetStyleVector StyleSheet::getStyleSheetStyleByAtRule( const AtRuleType& atRuleType ) const {
|
||||
StyleSheetStyleVector
|
||||
StyleSheet::getStyleSheetStyleByAtRule( const AtRuleType& atRuleType ) const {
|
||||
StyleSheetStyleVector vector;
|
||||
for ( auto& node : mNodes )
|
||||
if ( node->getAtRuleType() == atRuleType )
|
||||
vector.push_back( node.get() );
|
||||
|
||||
std::sort( vector.begin(), vector.end(),
|
||||
[]( const StyleSheetStyle* left, const StyleSheetStyle* right ) {
|
||||
bool leftHasIt = left->hasProperty( PropertyId::FontStyle );
|
||||
bool rightHasIt = right->hasProperty( PropertyId::FontStyle );
|
||||
if ( leftHasIt && !rightHasIt )
|
||||
return false;
|
||||
if ( !leftHasIt && rightHasIt )
|
||||
return true;
|
||||
return leftHasIt && rightHasIt;
|
||||
} );
|
||||
std::sort( vector.begin(), vector.end(), []( const auto& left, const auto& right ) {
|
||||
bool leftHasIt = left->hasProperty( PropertyId::FontStyle );
|
||||
bool rightHasIt = right->hasProperty( PropertyId::FontStyle );
|
||||
return leftHasIt < rightHasIt;
|
||||
} );
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <eepp/ui/uimenubar.hpp>
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uithememanager.hpp>
|
||||
|
||||
#define PUGIXML_HEADER_ONLY
|
||||
#include <pugixml/pugixml.hpp>
|
||||
|
||||
@@ -15,6 +16,8 @@ UIMenuBar* UIMenuBar::New() {
|
||||
|
||||
UIMenuBar::UIMenuBar() :
|
||||
UIWidget( "menubar" ), mMenuHeight( 0 ), mCurrentMenu( nullptr ), mWaitingUp( nullptr ) {
|
||||
mFlags |= UI_LOADS_ITS_CHILDREN;
|
||||
|
||||
if ( !( mFlags & UI_ANCHOR_RIGHT ) )
|
||||
mFlags |= UI_ANCHOR_RIGHT;
|
||||
|
||||
|
||||
@@ -14,6 +14,23 @@
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
class UILineBreak : public UIRichText {
|
||||
public:
|
||||
static UILineBreak* New() { return eeNew( UILineBreak, () ); }
|
||||
|
||||
UILineBreak() : UIRichText( "br " ) {}
|
||||
|
||||
virtual Uint32 getType() const { return UI_TYPE_BR; }
|
||||
|
||||
bool isType( const Uint32& type ) const {
|
||||
return UILineBreak::getType() == type ? true : UINode::isType( type );
|
||||
}
|
||||
};
|
||||
|
||||
UIRichText* UIRichText::NewBr() {
|
||||
return UILineBreak::New();
|
||||
};
|
||||
|
||||
UIRichText* UIRichText::New() {
|
||||
return eeNew( UIRichText, () );
|
||||
}
|
||||
@@ -485,6 +502,9 @@ void UIRichText::rebuildRichText() {
|
||||
}
|
||||
spanChild = spanChild->getNextNode();
|
||||
}
|
||||
} else if ( widget->isType( UI_TYPE_BR ) ) {
|
||||
mRichText.addSpan( "\n",
|
||||
widget->asType<UILineBreak>()->getRichText().getFontStyleConfig() );
|
||||
} else {
|
||||
Rectf margin = widget->getLayoutPixelsMargin();
|
||||
|
||||
@@ -613,6 +633,15 @@ void UIRichText::positionChildren() {
|
||||
hitBoxes.clear();
|
||||
}
|
||||
|
||||
} else if ( widget->isType( UI_TYPE_BR ) ) {
|
||||
curCharIdx += 1;
|
||||
Vector2f pos;
|
||||
if ( widget->getPrevNode() && widget->getPrevNode()->isWidget() ) {
|
||||
pos = widget->getPrevNode()->asType<UIWidget>()->getPixelsPosition();
|
||||
pos.y += widget->getPrevNode()->getPixelsSize().getHeight();
|
||||
}
|
||||
widget->setPixelsPosition( pos );
|
||||
widget->setPixelsSize( { mSize.getWidth(), 0 } );
|
||||
} else {
|
||||
curCharIdx += 1;
|
||||
const auto* span = getNextCustomSpan();
|
||||
|
||||
@@ -271,6 +271,32 @@ std::vector<UIWidget*> UISceneNode::loadNode( pugi::xml_node node, Node* parent,
|
||||
for ( pugi::xml_node widget = node; widget; widget = widget.next_sibling() ) {
|
||||
clock.restart();
|
||||
|
||||
if ( String::iequals( widget.name(), "style" ) ) {
|
||||
CSS::StyleSheetParser parser;
|
||||
std::string styleContent;
|
||||
for ( pugi::xml_node child = widget.first_child(); child;
|
||||
child = child.next_sibling() ) {
|
||||
if ( child.type() == pugi::node_pcdata || child.type() == pugi::node_cdata ) {
|
||||
styleContent += child.value();
|
||||
}
|
||||
}
|
||||
|
||||
if ( parser.loadFromString( std::string_view{ styleContent } ) ) {
|
||||
parser.getStyleSheet().setMarker( marker );
|
||||
combineStyleSheet( parser.getStyleSheet(), false );
|
||||
}
|
||||
continue;
|
||||
} else if ( String::iequals( widget.name(), "link" ) ) {
|
||||
auto type = widget.attribute( "type" );
|
||||
auto href = widget.attribute( "href" );
|
||||
auto rel = widget.attribute( "rel" );
|
||||
if ( !href.empty() && ( String::iequals( type.value(), "text/css" ) ||
|
||||
String::iequals( rel.value(), "stylesheet" ) ) ) {
|
||||
loadCSS( href.as_string() );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
UIWidget* uiwidget = UIWidgetCreator::createFromName( widget.name() );
|
||||
|
||||
if ( NULL != uiwidget ) {
|
||||
@@ -303,28 +329,6 @@ std::vector<UIWidget*> UISceneNode::loadNode( pugi::xml_node node, Node* parent,
|
||||
}
|
||||
|
||||
uiwidget->onWidgetCreated();
|
||||
} else if ( String::iequals( widget.name(), "style" ) ) {
|
||||
CSS::StyleSheetParser parser;
|
||||
std::string styleContent;
|
||||
for ( pugi::xml_node child = widget.first_child(); child;
|
||||
child = child.next_sibling() ) {
|
||||
if ( child.type() == pugi::node_pcdata || child.type() == pugi::node_cdata ) {
|
||||
styleContent += child.value();
|
||||
}
|
||||
}
|
||||
|
||||
if ( parser.loadFromString( std::string_view{ styleContent } ) ) {
|
||||
parser.getStyleSheet().setMarker( marker );
|
||||
combineStyleSheet( parser.getStyleSheet(), false );
|
||||
}
|
||||
} else if ( String::iequals( widget.name(), "link" ) ) {
|
||||
auto type = widget.attribute( "type" );
|
||||
auto href = widget.attribute( "href" );
|
||||
auto rel = widget.attribute( "rel" );
|
||||
if ( !href.empty() && ( String::iequals( type.value(), "text/css" ) ||
|
||||
String::iequals( rel.value(), "stylesheet" ) ) ) {
|
||||
loadCSS( href.as_string() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,11 +162,16 @@ void UIWidgetCreator::createBaseWidgetList() {
|
||||
registeredWidget["pre"] = UIRichText::NewPre;
|
||||
registeredWidget["img"] = [] { return UIImage::NewWithTag( "img" ); };
|
||||
registeredWidget["input"] = UITextInput::New;
|
||||
registeredWidget["header"] = [] { return UIRichText::NewWithTag( "header" ); };
|
||||
registeredWidget["article"] = [] { return UIRichText::NewWithTag( "article" ); };
|
||||
registeredWidget["footer"] = [] { return UIRichText::NewWithTag( "footer" ); };
|
||||
registeredWidget["main"] = [] { return UIRichText::NewWithTag( "main" ); };
|
||||
registeredWidget["nav"] = [] { return UIRichText::NewWithTag( "nav" ); };
|
||||
registeredWidget["center"] = [] { return UIRichText::NewWithTag( "center" ); };
|
||||
registeredWidget["html"] = [] { return UIRichText::NewWithTag( "html" ); };
|
||||
registeredWidget["head"] = [] { return UIWidget::NewWithTag( "head" ); };
|
||||
registeredWidget["body"] = [] { return UIRichText::NewWithTag( "body" ); };
|
||||
registeredWidget["form"] = [] { return UIRichText::NewWithTag( "form" ); };
|
||||
registeredWidget["table"] = UIHTMLTable::New;
|
||||
registeredWidget["tr"] = UIHTMLTableRow::New;
|
||||
registeredWidget["thead"] = UIHTMLTableHead::New;
|
||||
@@ -182,6 +187,9 @@ void UIWidgetCreator::createBaseWidgetList() {
|
||||
UIWidget* UIWidgetCreator::createFromName( const std::string& widgetName ) {
|
||||
createBaseWidgetList();
|
||||
|
||||
if ( widgetName.empty() )
|
||||
return nullptr;
|
||||
|
||||
std::string lwidgetName( String::toLower( widgetName ) );
|
||||
|
||||
if ( registeredWidget.find( lwidgetName ) != registeredWidget.end() ) {
|
||||
@@ -192,7 +200,9 @@ UIWidget* UIWidgetCreator::createFromName( const std::string& widgetName ) {
|
||||
return widgetCallback[lwidgetName]( lwidgetName );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
eePRINTL( "UIWidgetCreator::createFromName: \"%s\" not found", widgetName.c_str() );
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void UIWidgetCreator::addCustomWidgetCallback( const std::string& widgetName,
|
||||
|
||||
@@ -10,6 +10,12 @@ EE_MAIN_FUNC int main( int, char** ) {
|
||||
auto win = app.getWindow();
|
||||
auto ui = app.getUI();
|
||||
|
||||
FontTrueType* remixIconFont = FontTrueType::New( "icon", "assets/fonts/remixicon.ttf" );
|
||||
FontTrueType* noniconsFont = FontTrueType::New( "nonicons", "assets/fonts/nonicons.ttf" );
|
||||
FontTrueType* codIconFont = FontTrueType::New( "codicon", "assets/fonts/codicon.ttf" );
|
||||
ui->getUIIconThemeManager()->setCurrentTheme(
|
||||
IconManager::init( "icons", remixIconFont, noniconsFont, codIconFont ) );
|
||||
|
||||
ui->setColorSchemePreference( ColorSchemeExtPreference::Light );
|
||||
|
||||
ui->loadLayoutFromString( R"xml(
|
||||
|
||||
@@ -921,7 +921,7 @@ UTEST( UIRichText, MarginsTest ) {
|
||||
ASSERT_TRUE( d2 != nullptr );
|
||||
|
||||
sceneNode->update( Time::Zero );
|
||||
|
||||
|
||||
// Check the layout position of the first div
|
||||
Vector2f pos1 = d1->getPixelsPosition();
|
||||
// margin left is 40px, top is 10px, so position inside richtext should be (40, 10)
|
||||
@@ -933,7 +933,7 @@ UTEST( UIRichText, MarginsTest ) {
|
||||
Vector2f pos2 = d2->getPixelsPosition();
|
||||
// The widgets flow inline (horizontally) since total width < 800.
|
||||
// d1 footprint width: 40 (left) + 50 (width) + 20 (right) = 110.
|
||||
// d2 left margin: 5.
|
||||
// d2 left margin: 5.
|
||||
// Therefore d2 x position = 110 + 5 = 115.
|
||||
// Line height is determined by max footprint height.
|
||||
// d1 footprint height: 10 + 50 + 30 = 90.
|
||||
@@ -954,3 +954,71 @@ UTEST( UIRichText, MarginsTest ) {
|
||||
eeDelete( sceneNode );
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( UIRichText, ForcedLineBreak ) {
|
||||
Engine::instance()->createWindow( WindowSettings( 800, 600, "BR Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, {}, 1, false,
|
||||
true ) );
|
||||
|
||||
FileSystem::changeWorkingDirectory( Sys::getProcessPath() );
|
||||
|
||||
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
||||
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
||||
|
||||
ASSERT_TRUE( font->loaded() );
|
||||
FontFamily::loadFromRegular( font );
|
||||
|
||||
UISceneNode* sceneNode = UISceneNode::New();
|
||||
sceneNode->getUIThemeManager()->setDefaultFont( font );
|
||||
|
||||
String xml = R"xml(<richtext id="rt">Line 1<br/>Line 2</richtext>)xml";
|
||||
|
||||
sceneNode->loadLayoutFromString( xml );
|
||||
UIRichText* rt = sceneNode->find<UIRichText>( "rt" );
|
||||
ASSERT_TRUE( rt != nullptr );
|
||||
|
||||
sceneNode->update( Time::Zero );
|
||||
|
||||
const auto& richText = rt->getRichText();
|
||||
EXPECT_EQ( richText.getLines().size(), (size_t)3 );
|
||||
|
||||
eeDelete( sceneNode );
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( UIRichText, CustomBRHeight ) {
|
||||
Engine::instance()->createWindow( WindowSettings( 800, 600, "BR Test", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, {}, 1, false,
|
||||
true ) );
|
||||
|
||||
FontTrueType* font = FontTrueType::New( "NotoSans-Regular" );
|
||||
font->loadFromFile( "../assets/fonts/NotoSans-Regular.ttf" );
|
||||
|
||||
ASSERT_TRUE( font->loaded() );
|
||||
FontFamily::loadFromRegular( font );
|
||||
|
||||
UISceneNode* sceneNode = UISceneNode::New();
|
||||
sceneNode->getUIThemeManager()->setDefaultFont( font );
|
||||
|
||||
String xml = R"xml(<richtext id="rt">Line 1<br font-size="50px"/>Line 2</richtext>)xml";
|
||||
|
||||
sceneNode->loadLayoutFromString( xml );
|
||||
UIRichText* rt = sceneNode->find<UIRichText>( "rt" );
|
||||
ASSERT_TRUE( rt != nullptr );
|
||||
|
||||
sceneNode->update( Time::Zero );
|
||||
|
||||
const auto& richText = rt->getRichText();
|
||||
const auto& lines = richText.getLines();
|
||||
EXPECT_EQ( lines.size(), (size_t)3 );
|
||||
|
||||
if ( lines.size() >= 2 ) {
|
||||
EXPECT_GT( lines[0].height, lines[1].height );
|
||||
EXPECT_GT( lines[2].height, 0.f );
|
||||
}
|
||||
|
||||
eeDelete( sceneNode );
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user