From d276aa5bc783da5d1079efc4ba2a7cbe8be65285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Tue, 20 Feb 2024 00:34:52 -0300 Subject: [PATCH] Improve UICheckBox in different pixel densities. Improve stylesheet units printing. Added `dpr` as device-pixel rounded stylesheet length unit. Fixes in 7GUIs Cells. --- bin/assets/ui/breeze.css | 2 +- docs/articles/cssspecification.md | 2 +- include/eepp/ui/css/stylesheetlength.hpp | 1 + src/eepp/system/time.cpp | 4 +- src/eepp/ui/abstract/uiabstracttableview.cpp | 2 +- src/eepp/ui/css/stylesheetlength.cpp | 19 +++++---- src/eepp/ui/uicodeeditor.cpp | 4 +- src/eepp/ui/uiconsole.cpp | 4 +- src/eepp/ui/uitextinput.cpp | 2 +- src/eepp/ui/uitextview.cpp | 2 +- src/eepp/ui/uitooltip.cpp | 2 +- src/eepp/ui/uiviewpager.cpp | 6 +-- src/eepp/ui/uiwidget.cpp | 42 +++++++++++--------- src/examples/7guis/cells/cells.cpp | 8 ++++ src/examples/7guis/cells/formula.cpp | 2 + src/examples/7guis/cells/spreadsheet.cpp | 39 +++++++++++++++--- src/examples/7guis/cells/spreadsheet.hpp | 10 ++++- src/tools/ecode/ecode.cpp | 3 +- 18 files changed, 105 insertions(+), 49 deletions(-) diff --git a/bin/assets/ui/breeze.css b/bin/assets/ui/breeze.css index 5d84bfa9a..16c99f5e0 100644 --- a/bin/assets/ui/breeze.css +++ b/bin/assets/ui/breeze.css @@ -225,7 +225,7 @@ CheckBox:hover CheckBox::inactive { CheckBox::active { border-color: var(--primary); background-image: rectangle(solid, var(--primary)); - background-size: 70% 70%; + background-size: 8dpru 8dpru; background-position: center; } diff --git a/docs/articles/cssspecification.md b/docs/articles/cssspecification.md index 46243d1a4..0ba74abc7 100644 --- a/docs/articles/cssspecification.md +++ b/docs/articles/cssspecification.md @@ -2511,7 +2511,7 @@ Read [length](https://developer.mozilla.org/en-US/docs/Web/CSS/length) documenta * Supported lenghts: `em`, `rem`, `pt`, `pc`, `in`, `cm`, `mm`, `vw`, `vh`, `vmin`, `vmax`. -* Also adds: `dp` as [Device-independent pixel](https://en.wikipedia.org/wiki/Device-independent_pixel). Plus `dprd` (dp rounded down) and `dpru` (dp rounded up). +* Also adds: `dp` as [Device-independent pixel](https://en.wikipedia.org/wiki/Device-independent_pixel). Plus `dpr` (dp rounded), `dprd` (dp rounded down) and `dpru` (dp rounded up). --- diff --git a/include/eepp/ui/css/stylesheetlength.hpp b/include/eepp/ui/css/stylesheetlength.hpp index 3976a998f..6b7e129e9 100644 --- a/include/eepp/ui/css/stylesheetlength.hpp +++ b/include/eepp/ui/css/stylesheetlength.hpp @@ -32,6 +32,7 @@ class EE_API StyleSheetLength { Rem, Dprd, Dpru, + Dpr, }; static Unit unitFromString( std::string unitStr ); diff --git a/src/eepp/system/time.cpp b/src/eepp/system/time.cpp index 3fcc278b7..e29a7f240 100644 --- a/src/eepp/system/time.cpp +++ b/src/eepp/system/time.cpp @@ -63,8 +63,8 @@ std::string Time::toString() const { if ( asSeconds() < 1 ) { if ( asMilliseconds() == static_cast( (Int64)asMilliseconds() ) ) - return String::format( "%.fms", asMilliseconds() ); - return String::format( "%.2fms", asMilliseconds() ); + return String::fromFloat( asMilliseconds() ); + return String::fromFloat( asMilliseconds() ); } else if ( totalSeconds < 60 ) { return String::format( "%lus", static_cast( totalSeconds ) ); } diff --git a/src/eepp/ui/abstract/uiabstracttableview.cpp b/src/eepp/ui/abstract/uiabstracttableview.cpp index d63a05836..1d7a5a088 100644 --- a/src/eepp/ui/abstract/uiabstracttableview.cpp +++ b/src/eepp/ui/abstract/uiabstracttableview.cpp @@ -874,7 +874,7 @@ std::string UIAbstractTableView::getPropertyString( const PropertyDefinition* pr switch ( propertyDef->getPropertyId() ) { case PropertyId::RowHeight: - return String::format( "%.2fpx", getRowHeight() ); + return String::fromFloat( getRowHeight(), "px" ); default: return UIAbstractView::getPropertyString( propertyDef, propertyIndex ); } diff --git a/src/eepp/ui/css/stylesheetlength.cpp b/src/eepp/ui/css/stylesheetlength.cpp index ddb9cfb4b..b7cbbf9df 100644 --- a/src/eepp/ui/css/stylesheetlength.cpp +++ b/src/eepp/ui/css/stylesheetlength.cpp @@ -28,6 +28,7 @@ enum UnitHashes : String::HashType { Rem = String::hash( "rem" ), Dprd = String::hash( "dprd" ), Dpru = String::hash( "dpru" ), + Dpr = String::hash( "dpr" ), }; enum PercentagePositions : String::HashType { @@ -112,6 +113,8 @@ StyleSheetLength::Unit StyleSheetLength::unitFromString( std::string unitStr ) { return Unit::Dprd; case UnitHashes::Dpru: return Unit::Dpru; + case UnitHashes::Dpr: + return Unit::Dpr; } return Unit::Px; } @@ -156,6 +159,8 @@ std::string StyleSheetLength::unitToString( const StyleSheetLength::Unit& unit ) return "dprd"; case Unit::Dpru: return "dpru"; + case Unit::Dpr: + return "dpr"; } return "px"; } @@ -197,11 +202,13 @@ Float StyleSheetLength::asPixels( const Float& parentSize, const Sizef& viewSize case Unit::Dp: ret = PixelDensity::dpToPx( mValue ); break; + case Unit::Dpr: + return round( PixelDensity::dpToPx( mValue ) ); case Unit::Dprd: - ret = roundDown( PixelDensity::dpToPx( mValue ) ); + ret = Math::roundDown( PixelDensity::dpToPx( mValue ) ); break; case Unit::Dpru: - ret = roundUp( PixelDensity::dpToPx( mValue ) ); + ret = Math::roundUp( PixelDensity::dpToPx( mValue ) ); break; case Unit::Em: ret = Math::round( mValue * elFontSize ); @@ -300,12 +307,10 @@ StyleSheetLength StyleSheetLength::fromString( const std::string& str, const Flo } std::string StyleSheetLength::toString() const { - std::string res; - if ( (Int64)mValue == mValue ) - res = String::format( "%lld%s", (Int64)mValue, unitToString( mUnit ).c_str() ); - else - res = String::format( "%.2f%s", mValue, unitToString( mUnit ).c_str() ); + std::string res( String::format( "%.2f", mValue ) ); String::replace( res, ",", "." ); + String::numberCleanInPlace( res ); + res += unitToString( mUnit ); return res; } diff --git a/src/eepp/ui/uicodeeditor.cpp b/src/eepp/ui/uicodeeditor.cpp index d528f6110..8134ee6db 100644 --- a/src/eepp/ui/uicodeeditor.cpp +++ b/src/eepp/ui/uicodeeditor.cpp @@ -2283,11 +2283,11 @@ std::string UICodeEditor::getPropertyString( const PropertyDefinition* propertyD case PropertyId::FontFamily: return NULL != getFont() ? getFont()->getName() : ""; case PropertyId::FontSize: - return String::format( "%.2fpx", getFontSize() ); + return String::fromFloat( getFontSize(), "px" ); case PropertyId::FontStyle: return Text::styleFlagToString( getFontStyle() ); case PropertyId::TextStrokeWidth: - return String::toString( PixelDensity::dpToPx( getOutlineThickness() ) ); + return String::fromFloat( PixelDensity::dpToPx( getOutlineThickness() ), "px" ); case PropertyId::TextStrokeColor: return getOutlineColor().toHexString(); case PropertyId::TextSelection: diff --git a/src/eepp/ui/uiconsole.cpp b/src/eepp/ui/uiconsole.cpp index 45b721356..aa416ffb7 100644 --- a/src/eepp/ui/uiconsole.cpp +++ b/src/eepp/ui/uiconsole.cpp @@ -232,11 +232,11 @@ std::string UIConsole::getPropertyString( const PropertyDefinition* propertyDef, case PropertyId::FontFamily: return NULL != getFont() ? getFont()->getName() : ""; case PropertyId::FontSize: - return String::format( "%.2fpx", getFontSize() ); + return String::fromFloat( getFontSize(), "px" ); case PropertyId::FontStyle: return Text::styleFlagToString( getFontStyleConfig().getFontStyle() ); case PropertyId::TextStrokeWidth: - return String::toString( PixelDensity::dpToPx( getFontOutlineThickness() ) ); + return String::fromFloat( PixelDensity::dpToPx( getFontOutlineThickness() ), "px" ); case PropertyId::TextStrokeColor: return getFontOutlineColor().toHexString(); default: diff --git a/src/eepp/ui/uitextinput.cpp b/src/eepp/ui/uitextinput.cpp index bada546ea..bbdb85b9f 100644 --- a/src/eepp/ui/uitextinput.cpp +++ b/src/eepp/ui/uitextinput.cpp @@ -477,7 +477,7 @@ std::string UITextInput::getPropertyString( const PropertyDefinition* propertyDe case PropertyId::HintFontStyle: return Text::styleFlagToString( getHintFontStyle() ); case PropertyId::HintStrokeWidth: - return String::toString( PixelDensity::dpToPx( getHintOutlineThickness() ) ); + return String::fromFloat( PixelDensity::dpToPx( getHintOutlineThickness() ), "px" ); case PropertyId::HintStrokeColor: return getHintOutlineColor().toHexString(); default: diff --git a/src/eepp/ui/uitextview.cpp b/src/eepp/ui/uitextview.cpp index e8549b51c..d74c3f155 100644 --- a/src/eepp/ui/uitextview.cpp +++ b/src/eepp/ui/uitextview.cpp @@ -803,7 +803,7 @@ std::string UITextView::getPropertyString( const PropertyDefinition* propertyDef case PropertyId::FontStyle: return Text::styleFlagToString( getFontStyle() ); case PropertyId::TextStrokeWidth: - return String::toString( PixelDensity::dpToPx( getOutlineThickness() ) ); + return String::fromFloat( PixelDensity::dpToPx( getOutlineThickness() ), "px" ); case PropertyId::TextStrokeColor: return getOutlineColor().toHexString(); case PropertyId::Wordwrap: diff --git a/src/eepp/ui/uitooltip.cpp b/src/eepp/ui/uitooltip.cpp index 3167ded77..be7c13ee8 100644 --- a/src/eepp/ui/uitooltip.cpp +++ b/src/eepp/ui/uitooltip.cpp @@ -431,7 +431,7 @@ std::string UITooltip::getPropertyString( const PropertyDefinition* propertyDef, case PropertyId::FontStyle: return Text::styleFlagToString( getFontStyle() ); case PropertyId::TextStrokeWidth: - return String::toString( PixelDensity::dpToPx( getOutlineThickness() ) ); + return String::fromFloat( PixelDensity::dpToPx( getOutlineThickness() ), "px" ); case PropertyId::TextStrokeColor: return getOutlineColor().toHexString(); case PropertyId::TextAlign: diff --git a/src/eepp/ui/uiviewpager.cpp b/src/eepp/ui/uiviewpager.cpp index 1073060b9..d43be51f7 100644 --- a/src/eepp/ui/uiviewpager.cpp +++ b/src/eepp/ui/uiviewpager.cpp @@ -293,11 +293,11 @@ std::string UIViewPager::getPropertyString( const PropertyDefinition* propertyDe case PropertyId::Orientation: return getOrientation() == UIOrientation::Horizontal ? "horizontal" : "vertical"; case PropertyId::DragResistance: - return String::format( "%.2f", mDragResistance ); + return String::fromFloat( mDragResistance ); case PropertyId::ChangePagePercent: - return String::format( "%.2f", mChangePagePercent ); + return String::fromFloat( mChangePagePercent ); case PropertyId::MaxEdgeResistance: - return String::format( "%.2f", mMaxEdgeResistance ); + return String::fromFloat( mMaxEdgeResistance ); case PropertyId::PageTransitionDuration: return mPageTransitionDuration.toString(); case PropertyId::TimingFunction: diff --git a/src/eepp/ui/uiwidget.cpp b/src/eepp/ui/uiwidget.cpp index 3888d9f31..44b57f4c5 100644 --- a/src/eepp/ui/uiwidget.cpp +++ b/src/eepp/ui/uiwidget.cpp @@ -1391,13 +1391,13 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef, case PropertyId::Height: return String::fromFloat( getSize().getHeight(), "dp" ); case PropertyId::MarginLeft: - return String::format( "%.2fdp", getLayoutMargin().Left ); + return String::fromFloat( getLayoutMargin().Left, "dp" ); case PropertyId::MarginTop: - return String::format( "%.2fdp", getLayoutMargin().Top ); + return String::fromFloat( getLayoutMargin().Top, "dp" ); case PropertyId::MarginRight: - return String::format( "%.2fdp", getLayoutMargin().Right ); + return String::fromFloat( getLayoutMargin().Right, "dp" ); case PropertyId::MarginBottom: - return String::format( "%.2fdp", getLayoutMargin().Bottom ); + return String::fromFloat( getLayoutMargin().Bottom, "dp" ); case PropertyId::PaddingLeft: return String::fromFloat( getPadding().Left, "dp" ); case PropertyId::PaddingTop: @@ -1495,21 +1495,27 @@ std::string UIWidget::getPropertyString( const PropertyDefinition* propertyDef, case PropertyId::BorderBottomWidth: return String::fromFloat( setBorderEnabled( true )->getBorders().bottom.width, "px" ); case PropertyId::BorderTopLeftRadius: - return String::format( "%.2fpx %.2fpx", - setBorderEnabled( true )->getBorders().radius.topLeft.x, - getBorder()->getBorders().radius.topLeft.y ); + return String::format( + "%s %s", + String::fromFloat( setBorderEnabled( true )->getBorders().radius.topLeft.x, "px" ), + String::fromFloat( getBorder()->getBorders().radius.topLeft.y, "px" ) ); case PropertyId::BorderTopRightRadius: - return String::format( "%.2fpx %.2fpx", - setBorderEnabled( true )->getBorders().radius.topRight.x, - getBorder()->getBorders().radius.topRight.y ); + return String::format( + "%s %s", + String::fromFloat( setBorderEnabled( true )->getBorders().radius.topRight.x, "px" ), + String::fromFloat( getBorder()->getBorders().radius.topRight.y, "px" ) ); case PropertyId::BorderBottomLeftRadius: - return String::format( "%.2fpx %.2fpx", - setBorderEnabled( true )->getBorders().radius.bottomLeft.x, - getBorder()->getBorders().radius.bottomLeft.y ); + return String::format( + "%s %s", + String::fromFloat( setBorderEnabled( true )->getBorders().radius.bottomLeft.x, + "px" ), + String::fromFloat( getBorder()->getBorders().radius.bottomLeft.y, "px" ) ); case PropertyId::BorderBottomRightRadius: - return String::format( "%.2fpx %.2fpx", - setBorderEnabled( true )->getBorders().radius.bottomRight.x, - getBorder()->getBorders().radius.bottomRight.y ); + return String::format( + "%s %s", + String::fromFloat( setBorderEnabled( true )->getBorders().radius.bottomRight.x, + "px" ), + String::fromFloat( getBorder()->getBorders().radius.bottomRight.y, "px" ) ); case PropertyId::BorderSmooth: return mBorder ? ( mBorder->isSmooth() ? "true" : "false" ) : "false"; case PropertyId::BackgroundSmooth: @@ -1968,7 +1974,7 @@ std::string UIWidget::getLayoutWidthPolicyString() const { return "match_parent"; else if ( rules == SizePolicy::WrapContent ) return "wrap_content"; - return String::toString( getSize().getHeight() ) + "dp"; + return String::fromFloat( getSize().getHeight(), "dp" ); } std::string UIWidget::getLayoutHeightPolicyString() const { @@ -1978,7 +1984,7 @@ std::string UIWidget::getLayoutHeightPolicyString() const { return "match_parent"; else if ( rules == SizePolicy::WrapContent ) return "wrap_content"; - return String::toString( getSize().getHeight() ) + "dp"; + return String::fromFloat( getSize().getHeight(), "dp" ); } static std::string getGravityStringFromUint( const Uint32& gravity ) { diff --git a/src/examples/7guis/cells/cells.cpp b/src/examples/7guis/cells/cells.cpp index 3acb05257..1127ebb6a 100644 --- a/src/examples/7guis/cells/cells.cpp +++ b/src/examples/7guis/cells/cells.cpp @@ -26,12 +26,20 @@ EE_MAIN_FUNC int main( int, char** ) { table->setColumnsWidth( PixelDensity::dpToPx( 80 ) ); table->setRowHeaderWidth( PixelDensity::dpToPx( 32 ) ); table->setSelectionType( UITableView::SelectionType::Cell ); + table->setRowSearchByName( false ); table->setEditable( true ); table->setEditTriggers( UIAbstractView::EditTrigger::DoubleClicked | UIAbstractTableView::EditTrigger::EditKeyPressed ); table->setEditShortcuts( { { KEY_F2 }, { KEY_RETURN }, { KEY_KP_ENTER } } ); table->setSelection( model->index( 0, 0 ) ); table->setFocus(); + table->on( Event::KeyDown, [table, model]( const Event* event ) { + if ( table->getSelection().first().isValid() && + event->asKeyEvent()->getKeyCode() == KEY_DELETE ) { + model->cell( table->getSelection().first() ).clear(); + model->invalidate( Model::UpdateFlag::DontInvalidateIndexes ); + } + } ); table->onCreateEditingDelegate = [table, model]( const ModelIndex& index ) -> ModelEditingDelegate* { auto ret = StringModelEditingDelegate::New(); diff --git a/src/examples/7guis/cells/formula.cpp b/src/examples/7guis/cells/formula.cpp index 8bccdca07..71a844348 100644 --- a/src/examples/7guis/cells/formula.cpp +++ b/src/examples/7guis/cells/formula.cpp @@ -54,6 +54,8 @@ void SheetFunction::initOpTable() { tot += val; return vals.empty() ? 0 : tot / vals.size(); } } ); + opTable.insert( { String::hash( "COUNT" ), + []( const std::vector& vals ) { return vals.size(); } } ); } std::vector SheetFunction::evalList( const std::vector>& args, diff --git a/src/examples/7guis/cells/spreadsheet.cpp b/src/examples/7guis/cells/spreadsheet.cpp index 06365fb82..b28224b12 100644 --- a/src/examples/7guis/cells/spreadsheet.cpp +++ b/src/examples/7guis/cells/spreadsheet.cpp @@ -16,20 +16,41 @@ void Cell::parseFormula( const std::string& formulaStr ) { Cell::Cell( std::string val, Spreadsheet& sheet ) : value( std::move( val ) ), sheet( sheet ) {} -void Cell::setData( std::string&& data ) { +Cell::~Cell() {} + +bool Cell::subscribeToObservers() { + if ( formula ) { + for ( const auto& ref : formula->getReferences( sheet ) ) { + if ( this == ref || hasObserver( ref ) ) { + unsubscribeFromObservers(); + return false; + } + ref->addObserver( this ); + } + } + return true; +} + +void Cell::unsubscribeFromObservers() { if ( formula ) { for ( const auto& ref : formula->getReferences( sheet ) ) ref->deleteObserver( this ); } +} + +void Cell::setData( std::string&& data ) { + unsubscribeFromObservers(); value = std::move( data ); parseFormula( value ); calc(); - if ( formula ) { - for ( const auto& ref : formula->getReferences( sheet ) ) - ref->addObserver( this ); + bool circular = !subscribeToObservers(); + if ( circular ) { + displayValue = "!CIRCULAR"; + formulaContainsErrors = true; + } else { + setChanged(); + notifyObservers(); } - setChanged(); - notifyObservers(); } std::optional Cell::eval() const { @@ -72,6 +93,12 @@ void Cell::calc() { setChanged(); } +void Cell::clear() { + value = displayValue = ""; + formula = {}; + formulaContainsErrors = false; +} + void Cell::update() { calc(); notifyObservers(); diff --git a/src/examples/7guis/cells/spreadsheet.hpp b/src/examples/7guis/cells/spreadsheet.hpp index 935b17941..78a883dee 100644 --- a/src/examples/7guis/cells/spreadsheet.hpp +++ b/src/examples/7guis/cells/spreadsheet.hpp @@ -32,6 +32,8 @@ class Observable { void notifyObservers(); + bool hasObserver( Observer* observer ) { return mObservers.count( observer ); } + protected: std::unordered_set mObservers; std::atomic mChanged{ false }; @@ -46,7 +48,7 @@ class Cell : public Observer, public Observable { public: Cell( std::string val, Spreadsheet& sheet ); - virtual ~Cell() {} + virtual ~Cell(); void setData( std::string&& data ); @@ -58,6 +60,8 @@ class Cell : public Observer, public Observable { void calc(); + void clear(); + void update(); bool hasFormula() const; @@ -74,6 +78,10 @@ class Cell : public Observer, public Observable { bool formulaContainsErrors{ false }; void parseFormula( const std::string& formulaStr ); + + bool subscribeToObservers(); + + void unsubscribeFromObservers(); }; class Spreadsheet : public Model { diff --git a/src/tools/ecode/ecode.cpp b/src/tools/ecode/ecode.cpp index 1c85eedfc..45bf09528 100644 --- a/src/tools/ecode/ecode.cpp +++ b/src/tools/ecode/ecode.cpp @@ -1057,8 +1057,7 @@ void App::setUIScaleFactor() { i18n( "set_ui_scale_factor", "Set the UI scale factor (pixel density):\nMinimum value is " "1, and maximum 6. Requires restart." ) ); msgBox->setTitle( mWindowTitle ); - msgBox->getTextInput()->setText( - String::numberClean( String::format( "%.2f", mConfig.windowState.pixelDensity ) ) ); + msgBox->getTextInput()->setText( String::fromFloat( mConfig.windowState.pixelDensity ) ); msgBox->setCloseShortcut( { KEY_ESCAPE, 0 } ); msgBox->showWhenReady(); msgBox->on( Event::OnConfirm, [this, msgBox]( const Event* ) {