mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 10:40:20 +03:00
Refactor CSS properties to use dense IDs and bitsets:
Introduce contiguous PropertyId and ShorthandId enums backed by name-to-ID maps, replacing hash-valued property identifiers throughout the style system. Replace PropertyIdSet's unordered set with a fixed-size bitset, eliminating heap allocations during style state changes while providing deterministic ascending iteration. Keep name hashes for stylesheet storage and unknown or custom properties, while using dense typed IDs for registered-property lookup and dispatch. Preserve property aliases and the public Checked compatibility identifier. Add transaction-end reconciliation for interdependent image sizing properties, deferring percentage-based calculations until their containing block is resolved. Keep formatting-context-owned sizes intact for table cells and inline content. Add validation and tests for dense built-in registration, custom IDs, aliases, bitset operations, allocation-free storage, unknown properties, property application order, and image sizing regressions.
This commit is contained in:
@@ -12,7 +12,9 @@ class EE_API ElementDefinition : NonCopyable {
|
||||
public:
|
||||
ElementDefinition( const StyleSheetStyleVector& styleSheetStyles );
|
||||
|
||||
StyleSheetProperty* getProperty( const Uint32& id );
|
||||
StyleSheetProperty* getProperty( const PropertyId& id );
|
||||
|
||||
StyleSheetProperty* getPropertyByNameHash( const String::HashType& id );
|
||||
|
||||
const PropertyIdSet& getPropertyIds() const;
|
||||
|
||||
|
||||
@@ -0,0 +1,217 @@
|
||||
#ifndef EE_UI_CSS_IDNAMEMAP_HPP
|
||||
#define EE_UI_CSS_IDNAMEMAP_HPP
|
||||
|
||||
#include <eepp/core/containers.hpp>
|
||||
#include <eepp/system/log.hpp>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace EE { namespace UI { namespace CSS {
|
||||
|
||||
/**
|
||||
* @brief Maps dense process-local IDs to canonical names and back.
|
||||
*
|
||||
* The map is the full-string reverse lookup for a dense ID space. It owns no
|
||||
* definitions: it only tracks which ID belongs to which canonical (or alias)
|
||||
* name. Built-in IDs must be registered with addBuiltin() before finalizeBuiltins()
|
||||
* seals the built-in range; runtime names then receive IDs via getOrCreateId().
|
||||
*
|
||||
* Numeric IDs are unstable internal identifiers. Names are the stable external
|
||||
* representation. All names passed into the map are expected to already be
|
||||
* lowercase and trimmed; the map performs no hidden normalization and no
|
||||
* hash-only equality.
|
||||
*/
|
||||
template <typename Id, std::size_t MaxIds> class IdNameMap {
|
||||
public:
|
||||
IdNameMap() {
|
||||
mNames.emplace_back(); // index zero is Invalid with an empty name
|
||||
mNextCustomId = static_cast<Id>( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Registers a built-in ID with its canonical name.
|
||||
*
|
||||
* Valid only before custom allocation begins. Rejects Invalid, IDs at or
|
||||
* beyond MaxIds, duplicate names, and assigning a different name to an
|
||||
* occupied ID.
|
||||
*
|
||||
* @return true on success.
|
||||
*/
|
||||
bool addBuiltin( Id id, const std::string& canonicalName ) {
|
||||
if ( mBuiltinsFinalized ) {
|
||||
EE::System::Log::error(
|
||||
"IdNameMap: cannot register built-in \"%s\" after finalization.",
|
||||
canonicalName.c_str() );
|
||||
return false;
|
||||
}
|
||||
const auto underlying = static_cast<std::underlying_type_t<Id>>( id );
|
||||
const auto maxUnderlying = static_cast<std::underlying_type_t<Id>>( MaxIds );
|
||||
if ( underlying == 0 ) {
|
||||
EE::System::Log::error( "IdNameMap: cannot register Invalid built-in \"%s\".",
|
||||
canonicalName.c_str() );
|
||||
return false;
|
||||
}
|
||||
if ( underlying >= maxUnderlying ) {
|
||||
EE::System::Log::error( "IdNameMap: built-in ID %d for \"%s\" is out of range.",
|
||||
underlying, canonicalName.c_str() );
|
||||
return false;
|
||||
}
|
||||
if ( mIdsByName.find( canonicalName ) != mIdsByName.end() ) {
|
||||
EE::System::Log::error( "IdNameMap: duplicate built-in name \"%s\".",
|
||||
canonicalName.c_str() );
|
||||
return false;
|
||||
}
|
||||
if ( underlying < mNames.size() && !mNames[underlying].empty() ) {
|
||||
EE::System::Log::error(
|
||||
"IdNameMap: built-in ID %d already bound to \"%s\", not \"%s\".", underlying,
|
||||
mNames[underlying].c_str(), canonicalName.c_str() );
|
||||
return false;
|
||||
}
|
||||
if ( mNames.size() <= underlying )
|
||||
mNames.resize( underlying + 1 );
|
||||
mNames[underlying] = canonicalName;
|
||||
mIdsByName.emplace( canonicalName, id );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds an alias that resolves to an existing ID.
|
||||
*
|
||||
* Only the reverse entry is added; no ID is occupied and the canonical name
|
||||
* is never replaced.
|
||||
*/
|
||||
bool addAlias( const std::string& alias, Id target ) {
|
||||
if ( !contains( target ) ) {
|
||||
EE::System::Log::error( "IdNameMap: alias \"%s\" targets an unknown ID.",
|
||||
alias.c_str() );
|
||||
return false;
|
||||
}
|
||||
const auto existing = mIdsByName.find( alias );
|
||||
if ( existing != mIdsByName.end() ) {
|
||||
if ( existing->second == target )
|
||||
return true;
|
||||
EE::System::Log::error( "IdNameMap: alias \"%s\" is already bound to another ID.",
|
||||
alias.c_str() );
|
||||
return false;
|
||||
}
|
||||
mIdsByName.emplace( alias, target );
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Seals the built-in range and enables runtime ID allocation.
|
||||
*
|
||||
* Verifies every slot in [1, FirstCustomId) is populated. After this call
|
||||
* addBuiltin() is permanently rejected.
|
||||
*
|
||||
* @return true when all built-in slots are populated.
|
||||
*/
|
||||
bool finalizeBuiltins() {
|
||||
const auto firstCustom = static_cast<std::underlying_type_t<Id>>( Id::FirstCustomId );
|
||||
bool complete = true;
|
||||
for ( std::size_t i = 1; i < firstCustom; ++i ) {
|
||||
if ( i >= mNames.size() || mNames[i].empty() ) {
|
||||
EE::System::Log::error( "IdNameMap: built-in ID %zu was never registered.", i );
|
||||
complete = false;
|
||||
}
|
||||
}
|
||||
if ( mNames.size() > firstCustom ) {
|
||||
EE::System::Log::error(
|
||||
"IdNameMap: built-in slots beyond FirstCustomId are populated." );
|
||||
complete = false;
|
||||
}
|
||||
if ( complete ) {
|
||||
mBuiltinsFinalized = true;
|
||||
mNextCustomId = Id::FirstCustomId;
|
||||
}
|
||||
return complete;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the ID for a canonical or alias name.
|
||||
*
|
||||
* @return Invalid when the name is unknown.
|
||||
*/
|
||||
Id getId( std::string_view name ) const {
|
||||
const auto it = mIdsByName.find( std::string( name ) );
|
||||
return it != mIdsByName.end() ? it->second : static_cast<Id>( 0 );
|
||||
}
|
||||
|
||||
Id getId( const std::string& name ) const {
|
||||
const auto it = mIdsByName.find( name );
|
||||
return it != mIdsByName.end() ? it->second : static_cast<Id>( 0 );
|
||||
}
|
||||
|
||||
Id getId( const char* name ) const { return getId( std::string_view( name ) ); }
|
||||
|
||||
/**
|
||||
* @brief Returns the canonical name for an ID.
|
||||
*
|
||||
* @return The empty invalid name for invalid, out-of-range, or unassigned IDs.
|
||||
*/
|
||||
const std::string& getName( Id id ) const {
|
||||
const auto underlying = static_cast<std::underlying_type_t<Id>>( id );
|
||||
if ( underlying == 0 || underlying >= mNames.size() )
|
||||
return mNames[0];
|
||||
return mNames[underlying];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the existing ID for a canonical name, or allocates a new custom ID.
|
||||
*
|
||||
* Only valid after finalizeBuiltins(). Reaching the capacity returns Invalid
|
||||
* and logs a clear error containing the rejected name.
|
||||
*/
|
||||
Id getOrCreateId( const std::string& canonicalName ) {
|
||||
if ( !mBuiltinsFinalized ) {
|
||||
EE::System::Log::error(
|
||||
"IdNameMap: getOrCreateId(\"%s\") called before finalizeBuiltins().",
|
||||
canonicalName.c_str() );
|
||||
return static_cast<Id>( 0 );
|
||||
}
|
||||
const auto existing = getId( canonicalName );
|
||||
if ( existing != static_cast<Id>( 0 ) )
|
||||
return existing;
|
||||
const auto next = static_cast<std::underlying_type_t<Id>>( mNextCustomId );
|
||||
if ( next >= static_cast<std::underlying_type_t<Id>>( MaxIds ) ) {
|
||||
EE::System::Log::error( "IdNameMap: ID capacity exhausted (max %zu), rejecting \"%s\".",
|
||||
MaxIds, canonicalName.c_str() );
|
||||
return static_cast<Id>( 0 );
|
||||
}
|
||||
if ( mNames.size() <= next )
|
||||
mNames.resize( next + 1 );
|
||||
mNames[next] = canonicalName;
|
||||
mIdsByName.emplace( canonicalName, static_cast<Id>( next ) );
|
||||
mNextCustomId = static_cast<Id>( next + 1 );
|
||||
return static_cast<Id>( next );
|
||||
}
|
||||
|
||||
bool contains( Id id ) const {
|
||||
const auto underlying = static_cast<std::underlying_type_t<Id>>( id );
|
||||
return underlying > 0 && underlying < mNames.size() && !mNames[underlying].empty();
|
||||
}
|
||||
|
||||
bool contains( std::string_view name ) const {
|
||||
return mIdsByName.find( std::string( name ) ) != mIdsByName.end();
|
||||
}
|
||||
|
||||
bool contains( const std::string& name ) const {
|
||||
return mIdsByName.find( name ) != mIdsByName.end();
|
||||
}
|
||||
|
||||
bool contains( const char* name ) const { return contains( std::string_view( name ) ); }
|
||||
|
||||
std::size_t size() const { return mIdsByName.size(); }
|
||||
|
||||
private:
|
||||
std::vector<std::string> mNames;
|
||||
UnorderedMap<std::string, Id> mIdsByName;
|
||||
Id mNextCustomId;
|
||||
bool mBuiltinsFinalized{ false };
|
||||
};
|
||||
|
||||
}}} // namespace EE::UI::CSS
|
||||
|
||||
#endif // EE_UI_CSS_IDNAMEMAP_HPP
|
||||
@@ -3,328 +3,10 @@
|
||||
|
||||
#include <eepp/config.hpp>
|
||||
#include <eepp/core/string.hpp>
|
||||
#include <eepp/ui/css/propertyids.hpp>
|
||||
|
||||
namespace EE { namespace UI { namespace CSS {
|
||||
|
||||
enum class PropertyId : Uint32 {
|
||||
Id = String::hash( "id" ),
|
||||
Class = String::hash( "class" ),
|
||||
X = String::hash( "x" ),
|
||||
Y = String::hash( "y" ),
|
||||
Width = String::hash( "width" ),
|
||||
Height = String::hash( "height" ),
|
||||
BackgroundColor = String::hash( "background-color" ),
|
||||
BackgroundImage = String::hash( "background-image" ),
|
||||
BackgroundTint = String::hash( "background-tint" ),
|
||||
BackgroundPositionX = String::hash( "background-position-x" ),
|
||||
BackgroundPositionY = String::hash( "background-position-y" ),
|
||||
BackgroundRepeat = String::hash( "background-repeat" ),
|
||||
BackgroundSize = String::hash( "background-size" ),
|
||||
BackgroundOrigin = String::hash( "background-origin" ),
|
||||
BackgroundClip = String::hash( "background-clip" ),
|
||||
BackgroundAttachment = String::hash( "background-attachment" ),
|
||||
ForegroundColor = String::hash( "foreground-color" ),
|
||||
ForegroundTint = String::hash( "foreground-tint" ),
|
||||
ForegroundImage = String::hash( "foreground-image" ),
|
||||
ForegroundPositionX = String::hash( "foreground-position-x" ),
|
||||
ForegroundPositionY = String::hash( "foreground-position-y" ),
|
||||
ForegroundRepeat = String::hash( "foreground-repeat" ),
|
||||
ForegroundSize = String::hash( "foreground-size" ),
|
||||
ForegroundTopLeftRadius = String::hash( "foreground-top-left-radius" ),
|
||||
ForegroundTopRightRadius = String::hash( "foreground-top-right-radius" ),
|
||||
ForegroundBottomLeftRadius = String::hash( "foreground-bottom-left-radius" ),
|
||||
ForegroundBottomRightRadius = String::hash( "foreground-bottom-right-radius" ),
|
||||
Visible = String::hash( "visible" ),
|
||||
Visibility = String::hash( "visibility" ),
|
||||
Enabled = String::hash( "enabled" ),
|
||||
Theme = String::hash( "theme" ),
|
||||
Skin = String::hash( "skin" ),
|
||||
SkinColor = String::hash( "skin-color" ),
|
||||
Gravity = String::hash( "gravity" ),
|
||||
Flags = String::hash( "flags" ),
|
||||
MarginLeft = String::hash( "margin-left" ),
|
||||
MarginRight = String::hash( "margin-right" ),
|
||||
MarginTop = String::hash( "margin-top" ),
|
||||
MarginBottom = String::hash( "margin-bottom" ),
|
||||
Tooltip = String::hash( "tooltip" ),
|
||||
LayoutWeight = String::hash( "layout-weight" ),
|
||||
LayoutGravity = String::hash( "layout-gravity" ),
|
||||
LayoutWidth = String::hash( "layout-width" ),
|
||||
LayoutHeight = String::hash( "layout-height" ),
|
||||
LayoutToLeftOf = String::hash( "layout-to-left-of" ),
|
||||
LayoutToRightOf = String::hash( "layout-to-right-of" ),
|
||||
LayoutToTopOf = String::hash( "layout-to-top-of" ),
|
||||
LayoutToBottomOf = String::hash( "layout-to-bottom-of" ),
|
||||
Clip = String::hash( "clip" ),
|
||||
Rotation = String::hash( "rotation" ),
|
||||
Scale = String::hash( "scale" ),
|
||||
RotationOriginPointX = String::hash( "rotation-origin-point-x" ),
|
||||
RotationOriginPointY = String::hash( "rotation-origin-point-y" ),
|
||||
ScaleOriginPointX = String::hash( "scale-origin-point-x" ),
|
||||
ScaleOriginPointY = String::hash( "scale-origin-point-y" ),
|
||||
BlendMode = String::hash( "blend-mode" ),
|
||||
PaddingLeft = String::hash( "padding-left" ),
|
||||
PaddingRight = String::hash( "padding-right" ),
|
||||
PaddingTop = String::hash( "padding-top" ),
|
||||
PaddingBottom = String::hash( "padding-bottom" ),
|
||||
Opacity = String::hash( "opacity" ),
|
||||
Cursor = String::hash( "cursor" ),
|
||||
Text = String::hash( "text" ),
|
||||
TextTransform = String::hash( "text-transform" ),
|
||||
Color = String::hash( "color" ),
|
||||
TextShadowColor = String::hash( "text-shadow-color" ),
|
||||
TextShadowOffset = String::hash( "text-shadow-offset" ),
|
||||
SelectionColor = String::hash( "selection-color" ),
|
||||
SelectionBackColor = String::hash( "selection-back-color" ),
|
||||
FontFamily = String::hash( "font-family" ),
|
||||
FontSize = String::hash( "font-size" ),
|
||||
FontStyle = String::hash( "font-style" ),
|
||||
FontWeight = String::hash( "font-weight" ),
|
||||
TextDecoration = String::hash( "text-decoration" ),
|
||||
Wordwrap = String::hash( "word-wrap" ),
|
||||
WhiteSpace = String::hash( "white-space" ),
|
||||
WhiteSpaceCollapse = String::hash( "white-space-collapse" ),
|
||||
TextStrokeWidth = String::hash( "text-stroke-width" ),
|
||||
TextStrokeColor = String::hash( "text-stroke-color" ),
|
||||
TextSelection = String::hash( "text-selection" ),
|
||||
TextAlign = String::hash( "text-align" ),
|
||||
Icon = String::hash( "icon" ),
|
||||
MinIconSize = String::hash( "min-icon-size" ),
|
||||
MinSize = String::hash( "min-size" ),
|
||||
MaxSize = String::hash( "max-size" ),
|
||||
Src = String::hash( "src" ),
|
||||
ScaleType = String::hash( "scale-type" ),
|
||||
Tint = String::hash( "tint" ),
|
||||
MaxTextLength = String::hash( "max-text-length" ),
|
||||
MinTabWidth = String::hash( "min-tab-width" ),
|
||||
MaxTabWidth = String::hash( "max-tab-width" ),
|
||||
TabClosable = String::hash( "tab-closable" ),
|
||||
TabsEdgesDiffSkin = String::hash( "tabs-edges-diff-skin" ),
|
||||
TabSeparation = String::hash( "tab-separation" ),
|
||||
TabHeight = String::hash( "tab-height" ),
|
||||
TabCloseButtonVisible = String::hash( "tab-close-button-visible" ),
|
||||
Selected = String::hash( "selected" ),
|
||||
Checked = String::hash( "checked" ),
|
||||
PopUpToRoot = String::hash( "popup-to-root" ),
|
||||
MaxVisibleItems = String::hash( "max-visible-items" ),
|
||||
SelectedIndex = String::hash( "selected-index" ),
|
||||
SelectedText = String::hash( "selected-text" ),
|
||||
ScrollBarStyle = String::hash( "scrollbar-style" ),
|
||||
RowHeight = String::hash( "row-height" ),
|
||||
VScrollMode = String::hash( "vscroll-mode" ),
|
||||
HScrollMode = String::hash( "hscroll-mode" ),
|
||||
ColumnMargin = String::hash( "column-margin" ),
|
||||
RowMargin = String::hash( "row-margin" ),
|
||||
ColumnMode = String::hash( "column-mode" ),
|
||||
RowMode = String::hash( "row-mode" ),
|
||||
ColumnWeight = String::hash( "column-weight" ),
|
||||
ColumnHeight = String::hash( "column-height" ),
|
||||
ColumnWidth = String::hash( "column-width" ),
|
||||
RowWeight = String::hash( "row-weight" ),
|
||||
ReverseDraw = String::hash( "reverse-draw" ),
|
||||
Orientation = String::hash( "orientation" ),
|
||||
Indeterminate = String::hash( "indeterminate" ),
|
||||
MaxProgress = String::hash( "max-progress" ),
|
||||
Progress = String::hash( "progress" ),
|
||||
FillColor = String::hash( "fill-color" ),
|
||||
Radius = String::hash( "radius" ),
|
||||
OutlineThickness = String::hash( "outline-thickness" ),
|
||||
AnimationSpeed = String::hash( "animation-speed" ),
|
||||
ArcStartAngle = String::hash( "arc-start-angle" ),
|
||||
MinWidth = String::hash( "min-width" ),
|
||||
MinHeight = String::hash( "min-height" ),
|
||||
MaxWidth = String::hash( "max-width" ),
|
||||
MaxHeight = String::hash( "max-height" ),
|
||||
TotalSteps = String::hash( "total-steps" ),
|
||||
VerticalExpand = String::hash( "vertical-expand" ),
|
||||
DisplayPercent = String::hash( "display-percent" ),
|
||||
MovementSpeed = String::hash( "movement-speed" ),
|
||||
MinValue = String::hash( "min-value" ),
|
||||
MaxValue = String::hash( "max-value" ),
|
||||
Value = String::hash( "value" ),
|
||||
ClickStep = String::hash( "click-step" ),
|
||||
PageStep = String::hash( "page-step" ),
|
||||
BackgroundExpand = String::hash( "background-expand" ),
|
||||
ScrollBarMode = String::hash( "scrollbar-mode" ),
|
||||
HalfSlider = String::hash( "half-slider" ),
|
||||
Owns = String::hash( "owns" ),
|
||||
AllowEditing = String::hash( "allow-editing" ),
|
||||
Locked = String::hash( "locked" ),
|
||||
MaxLength = String::hash( "max-length" ),
|
||||
Numeric = String::hash( "numeric" ),
|
||||
AllowFloat = String::hash( "allow-float" ),
|
||||
TouchDrag = String::hash( "touch-drag" ),
|
||||
TouchDragDeceleration = String::hash( "touch-drag-deceleration" ),
|
||||
WindowTitle = String::hash( "window-title" ),
|
||||
WindowOpacity = String::hash( "window-opacity" ),
|
||||
WindowButtonsOffset = String::hash( "window-buttons-offset" ),
|
||||
WindowFlags = String::hash( "window-flags" ),
|
||||
WindowTitlebarSize = String::hash( "window-titlebar-size" ),
|
||||
WindowBorderSize = String::hash( "window-border-size" ),
|
||||
WindowMinSize = String::hash( "window-min-size" ),
|
||||
WindowBorderAutoSize = String::hash( "window-border-auto-size" ),
|
||||
WindowButtonsSeparation = String::hash( "window-buttons-separation" ),
|
||||
WindowCornerDistance = String::hash( "window-corner-distance" ),
|
||||
WindowTitlebarAutoSize = String::hash( "window-decoration-auto-size" ),
|
||||
WindowShadowColor = String::hash( "window-shadow-color" ),
|
||||
WindowShadowOffset = String::hash( "window-shadow-offset" ),
|
||||
WindowShadowSize = String::hash( "window-shadow-size" ),
|
||||
Hint = String::hash( "hint" ),
|
||||
HintColor = String::hash( "hint-color" ),
|
||||
HintShadowColor = String::hash( "hint-shadow-color" ),
|
||||
HintShadowOffset = String::hash( "hint-shadow-offset" ),
|
||||
HintFontFamily = String::hash( "hint-font-family" ),
|
||||
HintFontSize = String::hash( "hint-font-size" ),
|
||||
HintFontStyle = String::hash( "hint-font-style" ),
|
||||
HintStrokeWidth = String::hash( "hint-stroke-width" ),
|
||||
HintStrokeColor = String::hash( "hint-stroke-color" ),
|
||||
HintDisplay = String::hash( "hint-display" ),
|
||||
Transition = String::hash( "transition" ),
|
||||
TransitionDelay = String::hash( "transition-delay" ),
|
||||
TransitionDuration = String::hash( "transition-duration" ),
|
||||
TransitionProperty = String::hash( "transition-property" ),
|
||||
TransitionTimingFunction = String::hash( "transition-timing-function" ),
|
||||
Animation = String::hash( "animation" ),
|
||||
AnimationName = String::hash( "animation-name" ),
|
||||
AnimationDelay = String::hash( "animation-delay" ),
|
||||
AnimationDuration = String::hash( "animation-duration" ),
|
||||
AnimationFillMode = String::hash( "animation-fill-mode" ),
|
||||
AnimationIterationCount = String::hash( "animation-iteration-count" ),
|
||||
AnimationPlayState = String::hash( "animation-play-state" ),
|
||||
AnimationTimingFunction = String::hash( "animation-timing-function" ),
|
||||
DragResistance = String::hash( "drag-resistance" ),
|
||||
ChangePagePercent = String::hash( "change-page-percent" ),
|
||||
MaxEdgeResistance = String::hash( "max-edge-resistance" ),
|
||||
PageTransitionDuration = String::hash( "page-transition-duration" ),
|
||||
TimingFunction = String::hash( "timing-function" ),
|
||||
PageLocked = String::hash( "page-locked" ),
|
||||
BorderType = String::hash( "border-type" ),
|
||||
BorderLeftColor = String::hash( "border-left-color" ),
|
||||
BorderRightColor = String::hash( "border-right-color" ),
|
||||
BorderTopColor = String::hash( "border-top-color" ),
|
||||
BorderBottomColor = String::hash( "border-bottom-color" ),
|
||||
BorderLeftWidth = String::hash( "border-left-width" ),
|
||||
BorderRightWidth = String::hash( "border-right-width" ),
|
||||
BorderTopWidth = String::hash( "border-top-width" ),
|
||||
BorderBottomWidth = String::hash( "border-bottom-width" ),
|
||||
BorderLeftStyle = String::hash( "border-left-style" ),
|
||||
BorderRightStyle = String::hash( "border-right-style" ),
|
||||
BorderTopStyle = String::hash( "border-top-style" ),
|
||||
BorderBottomStyle = String::hash( "border-bottom-style" ),
|
||||
BorderTopLeftRadius = String::hash( "border-top-left-radius" ),
|
||||
BorderTopRightRadius = String::hash( "border-top-right-radius" ),
|
||||
BorderBottomLeftRadius = String::hash( "border-bottom-left-radius" ),
|
||||
BorderBottomRightRadius = String::hash( "border-bottom-right-radius" ),
|
||||
BorderSmooth = String::hash( "border-smooth" ),
|
||||
BoxSizing = String::hash( "box-sizing" ),
|
||||
BackgroundSmooth = String::hash( "background-smooth" ),
|
||||
ForegroundSmooth = String::hash( "foreground-smooth" ),
|
||||
TabBarHideOnSingleTab = String::hash( "tabbar-hide-on-single-tab" ),
|
||||
TabBarAllowRearrange = String::hash( "tabbar-allow-rearrange" ),
|
||||
TabBarAllowDragAndDrop = String::hash( "tabbar-allow-drag-and-drop-tabs" ),
|
||||
TabAllowSwitchTabsInEmptySpaces = String::hash( "tabbar-allow-switch-tabs-in-empty-spaces" ),
|
||||
SplitterPartition = String::hash( "splitter-partition" ),
|
||||
SplitterAlwaysShow = String::hash( "splitter-always-show" ),
|
||||
DroppableHoveringColor = String::hash( "droppable-hovering-color" ),
|
||||
TextAsFallback = String::hash( "text-as-fallback" ),
|
||||
SelectOnClick = String::hash( "select-on-click" ),
|
||||
LineSpacing = String::hash( "line-spacing" ),
|
||||
LineHeight = String::hash( "line-height" ),
|
||||
TextIndent = String::hash( "text-indent" ),
|
||||
TabSize = String::hash( "tab-size" ),
|
||||
GravityOwner = String::hash( "gravity-owner" ),
|
||||
Href = String::hash( "href" ),
|
||||
Focusable = String::hash( "focusable" ),
|
||||
InnerWidgetOrientation = String::hash( "inner-widget-orientation" ),
|
||||
Glyph = String::hash( "glyph" ),
|
||||
Name = String::hash( "name" ),
|
||||
RowValign = String::hash( "row-valign" ),
|
||||
TextOverflow = String::hash( "text-overflow" ),
|
||||
CheckMode = String::hash( "check-mode" ),
|
||||
EnableCodeEditorFlags = String::hash( "enable-editor-flags" ),
|
||||
DisableCodeEditorFlags = String::hash( "disable-editor-flags" ),
|
||||
LineWrapMode = String::hash( "line-wrap-mode" ),
|
||||
LineWrapType = String::hash( "line-wrap-type" ),
|
||||
DisplayOptions = String::hash( "display-options" ),
|
||||
MenuWidthMode = String::hash( "menu-width-mode" ),
|
||||
ExpandText = String::hash( "expand-text" ),
|
||||
ColSpan = String::hash( "colspan" ),
|
||||
TableLayout = String::hash( "table-layout" ),
|
||||
CellPadding = String::hash( "cellpadding" ),
|
||||
CellSpacing = String::hash( "cellspacing" ),
|
||||
Size = String::hash( "size" ),
|
||||
Type = String::hash( "type" ),
|
||||
Rows = String::hash( "rows" ),
|
||||
Cols = String::hash( "cols" ),
|
||||
InputMode = String::hash( "input-mode" ),
|
||||
Hidden = String::hash( "hidden" ),
|
||||
Open = String::hash( "open" ),
|
||||
Display = String::hash( "display" ),
|
||||
Position = String::hash( "position" ),
|
||||
Top = String::hash( "top" ),
|
||||
Right = String::hash( "right" ),
|
||||
Bottom = String::hash( "bottom" ),
|
||||
Left = String::hash( "left" ),
|
||||
ZIndex = String::hash( "z-index" ),
|
||||
ListStyleType = String::hash( "list-style-type" ),
|
||||
ListStylePosition = String::hash( "list-style-position" ),
|
||||
ListStyleImage = String::hash( "list-style-image" ),
|
||||
Float = String::hash( "float" ),
|
||||
Clear = String::hash( "clear" ),
|
||||
Action = String::hash( "action" ),
|
||||
Method = String::hash( "method" ),
|
||||
Enctype = String::hash( "enctype" ),
|
||||
Overflow = String::hash( "overflow" ),
|
||||
Target = String::hash( "target" ),
|
||||
For = String::hash( "for" ),
|
||||
UnicodeRange = String::hash( "unicode-range" ),
|
||||
AlignmentBaseline = String::hash( "alignment-baseline" ),
|
||||
FlexDirection = String::hash( "flex-direction" ),
|
||||
FlexWrap = String::hash( "flex-wrap" ),
|
||||
JustifyContent = String::hash( "justify-content" ),
|
||||
AlignItems = String::hash( "align-items" ),
|
||||
AlignContent = String::hash( "align-content" ),
|
||||
AlignSelf = String::hash( "align-self" ),
|
||||
FlexGrow = String::hash( "flex-grow" ),
|
||||
FlexShrink = String::hash( "flex-shrink" ),
|
||||
FlexBasis = String::hash( "flex-basis" ),
|
||||
Flex = String::hash( "flex" ),
|
||||
FlexFlow = String::hash( "flex-flow" ),
|
||||
Order = String::hash( "order" ),
|
||||
RowGap = String::hash( "row-gap" ),
|
||||
ColumnGap = String::hash( "column-gap" ),
|
||||
Gap = String::hash( "gap" ),
|
||||
Editable = String::hash( "editable" ),
|
||||
SelectionType = String::hash( "selection-type" ),
|
||||
SelectionKind = String::hash( "selection-kind" ),
|
||||
IconSize = String::hash( "icon-size" ),
|
||||
SortIconSize = String::hash( "sort-icon-size" ),
|
||||
MainColumn = String::hash( "main-column" ),
|
||||
RowHeaderWidth = String::hash( "row-header-width" ),
|
||||
TableFlags = String::hash( "table-flags" ),
|
||||
IndentWidth = String::hash( "indent-width" ),
|
||||
ExpanderIconSize = String::hash( "expander-icon-size" ),
|
||||
TableModel = String::hash( "table-model" ),
|
||||
GridTemplateRows = String::hash( "grid-template-rows" ),
|
||||
GridTemplateColumns = String::hash( "grid-template-columns" ),
|
||||
GridTemplateAreas = String::hash( "grid-template-areas" ),
|
||||
GridTemplate = String::hash( "grid-template" ),
|
||||
GridAutoRows = String::hash( "grid-auto-rows" ),
|
||||
GridAutoColumns = String::hash( "grid-auto-columns" ),
|
||||
GridAutoFlow = String::hash( "grid-auto-flow" ),
|
||||
Grid = String::hash( "grid" ),
|
||||
GridRowStart = String::hash( "grid-row-start" ),
|
||||
GridRowEnd = String::hash( "grid-row-end" ),
|
||||
GridColumnStart = String::hash( "grid-column-start" ),
|
||||
GridColumnEnd = String::hash( "grid-column-end" ),
|
||||
GridRow = String::hash( "grid-row" ),
|
||||
GridColumn = String::hash( "grid-column" ),
|
||||
GridArea = String::hash( "grid-area" ),
|
||||
JustifyItems = String::hash( "justify-items" ),
|
||||
JustifySelf = String::hash( "justify-self" ),
|
||||
Defer = String::hash( "defer" ),
|
||||
};
|
||||
|
||||
enum class PropertyType : Uint32 {
|
||||
Undefined,
|
||||
String,
|
||||
@@ -362,13 +44,15 @@ enum class PropertyRelativeTarget : Uint32 {
|
||||
|
||||
class EE_API PropertyDefinition {
|
||||
public:
|
||||
PropertyDefinition( const std::string& name, const std::string& defaultValue,
|
||||
const bool& inherited = false );
|
||||
PropertyDefinition( PropertyId propertyId, const std::string& name,
|
||||
const std::string& defaultValue, const bool& inherited = false );
|
||||
|
||||
const std::string& getName() const;
|
||||
|
||||
/** @brief Returns the canonical property-name hash, not the dense PropertyId. */
|
||||
const String::HashType& getId() const;
|
||||
|
||||
/** @brief Returns the dense identity used for dispatch and PropertyIdSet membership. */
|
||||
PropertyId getPropertyId() const;
|
||||
|
||||
const std::string& getDefaultValue() const;
|
||||
@@ -400,6 +84,7 @@ class EE_API PropertyDefinition {
|
||||
protected:
|
||||
std::string mName;
|
||||
String::HashType mId;
|
||||
PropertyId mPropertyId;
|
||||
std::vector<std::string> mAliases;
|
||||
std::vector<Uint32> mAliasesHash;
|
||||
std::string mDefaultValue;
|
||||
|
||||
@@ -0,0 +1,392 @@
|
||||
#ifndef EE_UI_CSS_PROPERTYIDS_HPP
|
||||
#define EE_UI_CSS_PROPERTYIDS_HPP
|
||||
|
||||
#include <eepp/config.hpp>
|
||||
|
||||
namespace EE { namespace UI { namespace CSS {
|
||||
|
||||
/**
|
||||
* Dense process-local CSS property identifiers.
|
||||
*
|
||||
* Numeric values are unstable internal implementation identifiers assigned at
|
||||
* compile time. They are never persisted, serialized, sent over IPC, or exposed as
|
||||
* stable values: names are the stable external representation. Every built-in is a
|
||||
* contiguous enum below NumDefinedIds; runtime-registered properties continue from
|
||||
* FirstCustomId. MaxNumIds is an exclusive capacity bound.
|
||||
*/
|
||||
enum class PropertyId : Uint16 {
|
||||
Invalid = 0,
|
||||
Id,
|
||||
Class,
|
||||
X,
|
||||
Y,
|
||||
Width,
|
||||
Height,
|
||||
BackgroundColor,
|
||||
BackgroundImage,
|
||||
BackgroundTint,
|
||||
BackgroundPositionX,
|
||||
BackgroundPositionY,
|
||||
BackgroundRepeat,
|
||||
BackgroundSize,
|
||||
BackgroundOrigin,
|
||||
BackgroundClip,
|
||||
BackgroundAttachment,
|
||||
ForegroundColor,
|
||||
ForegroundTint,
|
||||
ForegroundImage,
|
||||
ForegroundPositionX,
|
||||
ForegroundPositionY,
|
||||
ForegroundRepeat,
|
||||
ForegroundSize,
|
||||
ForegroundTopLeftRadius,
|
||||
ForegroundTopRightRadius,
|
||||
ForegroundBottomLeftRadius,
|
||||
ForegroundBottomRightRadius,
|
||||
Visible,
|
||||
Visibility,
|
||||
Enabled,
|
||||
Theme,
|
||||
Skin,
|
||||
SkinColor,
|
||||
Gravity,
|
||||
Flags,
|
||||
MarginLeft,
|
||||
MarginRight,
|
||||
MarginTop,
|
||||
MarginBottom,
|
||||
Tooltip,
|
||||
LayoutWeight,
|
||||
LayoutGravity,
|
||||
LayoutWidth,
|
||||
LayoutHeight,
|
||||
LayoutToLeftOf,
|
||||
LayoutToRightOf,
|
||||
LayoutToTopOf,
|
||||
LayoutToBottomOf,
|
||||
Clip,
|
||||
Rotation,
|
||||
Scale,
|
||||
RotationOriginPointX,
|
||||
RotationOriginPointY,
|
||||
ScaleOriginPointX,
|
||||
ScaleOriginPointY,
|
||||
BlendMode,
|
||||
PaddingLeft,
|
||||
PaddingRight,
|
||||
PaddingTop,
|
||||
PaddingBottom,
|
||||
Opacity,
|
||||
Cursor,
|
||||
Text,
|
||||
TextTransform,
|
||||
Color,
|
||||
TextShadowColor,
|
||||
TextShadowOffset,
|
||||
SelectionColor,
|
||||
SelectionBackColor,
|
||||
FontFamily,
|
||||
FontSize,
|
||||
FontStyle,
|
||||
FontWeight,
|
||||
TextDecoration,
|
||||
Wordwrap,
|
||||
WhiteSpace,
|
||||
WhiteSpaceCollapse,
|
||||
TextStrokeWidth,
|
||||
TextStrokeColor,
|
||||
TextSelection,
|
||||
TextAlign,
|
||||
Icon,
|
||||
MinIconSize,
|
||||
Src,
|
||||
ScaleType,
|
||||
Tint,
|
||||
MaxTextLength,
|
||||
MinTabWidth,
|
||||
MaxTabWidth,
|
||||
TabClosable,
|
||||
TabsEdgesDiffSkin,
|
||||
TabSeparation,
|
||||
TabHeight,
|
||||
TabCloseButtonVisible,
|
||||
Selected,
|
||||
/** Compatibility spelling: "checked" is an alias of the canonical "selected" property. */
|
||||
Checked = Selected,
|
||||
PopUpToRoot,
|
||||
MaxVisibleItems,
|
||||
SelectedIndex,
|
||||
SelectedText,
|
||||
ScrollBarStyle,
|
||||
RowHeight,
|
||||
VScrollMode,
|
||||
HScrollMode,
|
||||
ColumnMargin,
|
||||
RowMargin,
|
||||
ColumnMode,
|
||||
RowMode,
|
||||
ColumnWeight,
|
||||
ColumnWidth,
|
||||
RowWeight,
|
||||
ReverseDraw,
|
||||
Orientation,
|
||||
Indeterminate,
|
||||
MaxProgress,
|
||||
Progress,
|
||||
FillColor,
|
||||
Radius,
|
||||
OutlineThickness,
|
||||
AnimationSpeed,
|
||||
ArcStartAngle,
|
||||
MinWidth,
|
||||
MinHeight,
|
||||
MaxWidth,
|
||||
MaxHeight,
|
||||
TotalSteps,
|
||||
VerticalExpand,
|
||||
DisplayPercent,
|
||||
MovementSpeed,
|
||||
MinValue,
|
||||
MaxValue,
|
||||
Value,
|
||||
ClickStep,
|
||||
PageStep,
|
||||
BackgroundExpand,
|
||||
ScrollBarMode,
|
||||
HalfSlider,
|
||||
Owns,
|
||||
AllowEditing,
|
||||
Locked,
|
||||
MaxLength,
|
||||
Numeric,
|
||||
AllowFloat,
|
||||
TouchDrag,
|
||||
TouchDragDeceleration,
|
||||
WindowTitle,
|
||||
WindowOpacity,
|
||||
WindowButtonsOffset,
|
||||
WindowFlags,
|
||||
WindowTitlebarSize,
|
||||
WindowBorderSize,
|
||||
WindowMinSize,
|
||||
WindowBorderAutoSize,
|
||||
WindowButtonsSeparation,
|
||||
WindowCornerDistance,
|
||||
WindowTitlebarAutoSize,
|
||||
WindowShadowColor,
|
||||
WindowShadowOffset,
|
||||
WindowShadowSize,
|
||||
Hint,
|
||||
HintColor,
|
||||
HintShadowColor,
|
||||
HintShadowOffset,
|
||||
HintFontFamily,
|
||||
HintFontSize,
|
||||
HintFontStyle,
|
||||
HintStrokeWidth,
|
||||
HintStrokeColor,
|
||||
HintDisplay,
|
||||
Transition,
|
||||
TransitionDelay,
|
||||
TransitionDuration,
|
||||
TransitionProperty,
|
||||
TransitionTimingFunction,
|
||||
Animation,
|
||||
AnimationName,
|
||||
AnimationDelay,
|
||||
AnimationDirection,
|
||||
AnimationDuration,
|
||||
AnimationFillMode,
|
||||
AnimationIterationCount,
|
||||
AnimationPlayState,
|
||||
AnimationTimingFunction,
|
||||
DragResistance,
|
||||
ChangePagePercent,
|
||||
MaxEdgeResistance,
|
||||
TimingFunction,
|
||||
PageLocked,
|
||||
BorderType,
|
||||
BorderLeftColor,
|
||||
BorderRightColor,
|
||||
BorderTopColor,
|
||||
BorderBottomColor,
|
||||
BorderLeftWidth,
|
||||
BorderRightWidth,
|
||||
BorderTopWidth,
|
||||
BorderBottomWidth,
|
||||
BorderLeftStyle,
|
||||
BorderRightStyle,
|
||||
BorderTopStyle,
|
||||
BorderBottomStyle,
|
||||
BorderTopLeftRadius,
|
||||
BorderTopRightRadius,
|
||||
BorderBottomLeftRadius,
|
||||
BorderBottomRightRadius,
|
||||
BorderSmooth,
|
||||
BoxSizing,
|
||||
BackgroundSmooth,
|
||||
ForegroundSmooth,
|
||||
TabBarHideOnSingleTab,
|
||||
TabBarAllowRearrange,
|
||||
TabBarAllowDragAndDrop,
|
||||
TabAllowSwitchTabsInEmptySpaces,
|
||||
SplitterPartition,
|
||||
SplitterAlwaysShow,
|
||||
DroppableHoveringColor,
|
||||
TextAsFallback,
|
||||
SelectOnClick,
|
||||
LineSpacing,
|
||||
LineHeight,
|
||||
TextIndent,
|
||||
TabSize,
|
||||
GravityOwner,
|
||||
Href,
|
||||
Focusable,
|
||||
InnerWidgetOrientation,
|
||||
Glyph,
|
||||
Name,
|
||||
RowValign,
|
||||
TextOverflow,
|
||||
CheckMode,
|
||||
EnableCodeEditorFlags,
|
||||
DisableCodeEditorFlags,
|
||||
LineWrapMode,
|
||||
LineWrapType,
|
||||
DisplayOptions,
|
||||
MenuWidthMode,
|
||||
ExpandText,
|
||||
ColSpan,
|
||||
TableLayout,
|
||||
CellPadding,
|
||||
CellSpacing,
|
||||
Size,
|
||||
Type,
|
||||
Rows,
|
||||
Cols,
|
||||
InputMode,
|
||||
Hidden,
|
||||
Open,
|
||||
Display,
|
||||
Position,
|
||||
Top,
|
||||
Right,
|
||||
Bottom,
|
||||
Left,
|
||||
ZIndex,
|
||||
ListStyleType,
|
||||
ListStylePosition,
|
||||
ListStyleImage,
|
||||
Float,
|
||||
Clear,
|
||||
Action,
|
||||
Method,
|
||||
Enctype,
|
||||
Overflow,
|
||||
Target,
|
||||
For,
|
||||
UnicodeRange,
|
||||
AlignmentBaseline,
|
||||
FlexDirection,
|
||||
FlexWrap,
|
||||
JustifyContent,
|
||||
AlignItems,
|
||||
AlignContent,
|
||||
AlignSelf,
|
||||
FlexGrow,
|
||||
FlexShrink,
|
||||
FlexBasis,
|
||||
Order,
|
||||
RowGap,
|
||||
ColumnGap,
|
||||
Editable,
|
||||
SelectionType,
|
||||
SelectionKind,
|
||||
IconSize,
|
||||
SortIconSize,
|
||||
MainColumn,
|
||||
RowHeaderWidth,
|
||||
TableFlags,
|
||||
IndentWidth,
|
||||
ExpanderIconSize,
|
||||
TableModel,
|
||||
GridTemplateRows,
|
||||
GridTemplateColumns,
|
||||
GridTemplateAreas,
|
||||
GridAutoRows,
|
||||
GridAutoColumns,
|
||||
GridAutoFlow,
|
||||
GridRowStart,
|
||||
GridRowEnd,
|
||||
GridColumnStart,
|
||||
GridColumnEnd,
|
||||
GridRow,
|
||||
GridColumn,
|
||||
GridArea,
|
||||
JustifyItems,
|
||||
JustifySelf,
|
||||
Defer,
|
||||
NumDefinedIds,
|
||||
FirstCustomId = NumDefinedIds,
|
||||
MaxNumIds = 512,
|
||||
};
|
||||
|
||||
/**
|
||||
* Dense process-local CSS shorthand identifiers.
|
||||
*
|
||||
* Same identity rules as PropertyId, in a separate ID space: a shorthand is never
|
||||
* cast to a PropertyId even when its spelling matches a longhand.
|
||||
*/
|
||||
enum class ShorthandId : Uint8 {
|
||||
Invalid = 0,
|
||||
Margin,
|
||||
LayoutMargin,
|
||||
LayoutMarginUnderscore,
|
||||
Padding,
|
||||
Background,
|
||||
Foreground,
|
||||
BoxMargin,
|
||||
BackgroundPosition,
|
||||
ForegroundPosition,
|
||||
BorderColor,
|
||||
BorderWidth,
|
||||
BorderStyle,
|
||||
BorderRadius,
|
||||
ForegroundRadius,
|
||||
RotationOriginPoint,
|
||||
RotateOriginPoint,
|
||||
ScaleOriginPoint,
|
||||
MinSize,
|
||||
MaxSize,
|
||||
Border,
|
||||
TextShadow,
|
||||
HintShadow,
|
||||
BorderLeft,
|
||||
BorderRight,
|
||||
BorderTop,
|
||||
BorderBottom,
|
||||
ListStyle,
|
||||
Font,
|
||||
VerticalAlign,
|
||||
FlexFlow,
|
||||
Flex,
|
||||
Gap,
|
||||
GridTemplate,
|
||||
Grid,
|
||||
PlaceItems,
|
||||
PlaceSelf,
|
||||
PlaceContent,
|
||||
NumDefinedIds,
|
||||
FirstCustomId = NumDefinedIds,
|
||||
MaxNumIds = 255,
|
||||
};
|
||||
|
||||
static_assert( static_cast<Uint16>( PropertyId::NumDefinedIds ) <
|
||||
static_cast<Uint16>( PropertyId::MaxNumIds ),
|
||||
"PropertyId built-in count must stay below MaxNumIds" );
|
||||
static_assert( static_cast<Uint8>( ShorthandId::NumDefinedIds ) <
|
||||
static_cast<Uint8>( ShorthandId::MaxNumIds ),
|
||||
"ShorthandId built-in count must stay below MaxNumIds" );
|
||||
|
||||
}}} // namespace EE::UI::CSS
|
||||
|
||||
#endif // EE_UI_CSS_PROPERTYIDS_HPP
|
||||
@@ -1,37 +1,79 @@
|
||||
#ifndef EE_UI_CSS_PROPERTYIDSET_HPP
|
||||
#define EE_UI_CSS_PROPERTYIDSET_HPP
|
||||
|
||||
#include <eepp/core/containers.hpp>
|
||||
#include <eepp/ui/css/propertydefinition.hpp>
|
||||
#include <bitset>
|
||||
#include <eepp/core/debug.hpp>
|
||||
#include <eepp/ui/css/propertyids.hpp>
|
||||
|
||||
namespace EE { namespace UI { namespace CSS {
|
||||
|
||||
class PropertyIdSetIterator;
|
||||
|
||||
namespace detail {
|
||||
inline std::size_t bitsetFindFirst( const std::bitset<512>& bits ) {
|
||||
for ( std::size_t i = 0; i < bits.size(); ++i )
|
||||
if ( bits.test( i ) )
|
||||
return i;
|
||||
return bits.size();
|
||||
}
|
||||
|
||||
inline std::size_t bitsetFindNext( const std::bitset<512>& bits, std::size_t from ) {
|
||||
for ( std::size_t i = from + 1; i < bits.size(); ++i )
|
||||
if ( bits.test( i ) )
|
||||
return i;
|
||||
return bits.size();
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* @brief Fixed-capacity set of dense PropertyId values.
|
||||
*
|
||||
* Backed by a 512-bit std::bitset, so construction, clearing, copying, union,
|
||||
* intersection, and iteration perform zero heap allocations. Only successfully
|
||||
* registered property definitions occupy bits; unknown names never enter this
|
||||
* set. Iteration yields present IDs in ascending dense ID order.
|
||||
*/
|
||||
class EE_API PropertyIdSet {
|
||||
private:
|
||||
UnorderedSet<Uint32> mIds;
|
||||
std::bitset<512> mBits;
|
||||
|
||||
public:
|
||||
void insert( Uint32 id ) { mIds.insert( id ); }
|
||||
void insert( PropertyId id ) {
|
||||
const auto underlying = static_cast<std::size_t>( id );
|
||||
if ( underlying == 0 )
|
||||
return; // Invalid is a no-op
|
||||
if ( underlying >= mBits.size() ) {
|
||||
eeASSERTM( false, "PropertyId out of PropertyIdSet capacity" );
|
||||
return;
|
||||
}
|
||||
mBits.set( underlying );
|
||||
}
|
||||
|
||||
void clear() { mIds.clear(); }
|
||||
void clear() { mBits.reset(); }
|
||||
|
||||
void erase( Uint32 id ) { mIds.erase( id ); }
|
||||
void erase( PropertyId id ) {
|
||||
const auto underlying = static_cast<std::size_t>( id );
|
||||
if ( underlying == 0 )
|
||||
return; // Invalid is a no-op
|
||||
if ( underlying >= mBits.size() ) {
|
||||
eeASSERTM( false, "PropertyId out of PropertyIdSet capacity" );
|
||||
return;
|
||||
}
|
||||
mBits.reset( underlying );
|
||||
}
|
||||
|
||||
bool empty() const { return mIds.empty(); }
|
||||
bool empty() const { return mBits.none(); }
|
||||
|
||||
bool contains( Uint32 id ) const { return mIds.count( id ) == 1; }
|
||||
bool contains( PropertyId id ) const {
|
||||
const auto underlying = static_cast<std::size_t>( id );
|
||||
return underlying != 0 && underlying < mBits.size() && mBits.test( underlying );
|
||||
}
|
||||
|
||||
size_t size() const { return mIds.size(); }
|
||||
|
||||
bool operator==( const PropertyIdSet& other ) const { return mIds == other.mIds; }
|
||||
|
||||
bool operator!=( const PropertyIdSet& other ) const { return mIds != other.mIds; }
|
||||
size_t size() const { return mBits.count(); }
|
||||
|
||||
// Union with another set
|
||||
PropertyIdSet& operator|=( const PropertyIdSet& other ) {
|
||||
mIds.insert( other.mIds.begin(), other.mIds.end() );
|
||||
mBits |= other.mBits;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -43,79 +85,81 @@ class EE_API PropertyIdSet {
|
||||
|
||||
// Intersection with another set
|
||||
PropertyIdSet& operator&=( const PropertyIdSet& other ) {
|
||||
if ( !mIds.empty() && !other.mIds.empty() ) {
|
||||
for ( auto it = mIds.begin(); it != mIds.end(); )
|
||||
if ( other.mIds.count( *it ) == 0 )
|
||||
it = mIds.erase( it );
|
||||
else
|
||||
++it;
|
||||
} else {
|
||||
mIds.clear();
|
||||
}
|
||||
mBits &= other.mBits;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PropertyIdSet operator&( const PropertyIdSet& other ) const {
|
||||
PropertyIdSet result;
|
||||
if ( !mIds.empty() && !other.mIds.empty() ) {
|
||||
for ( Uint32 id : mIds )
|
||||
if ( other.mIds.count( id ) == 1 )
|
||||
result.mIds.insert( id );
|
||||
}
|
||||
PropertyIdSet result = *this;
|
||||
result &= other;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==( const PropertyIdSet& other ) const { return mBits == other.mBits; }
|
||||
|
||||
bool operator!=( const PropertyIdSet& other ) const { return mBits != other.mBits; }
|
||||
|
||||
// Iterator support. Iterates through all the PropertyIds that are set (contained).
|
||||
// @note: Modifying the container invalidates the iterators. Only const_iterators are provided.
|
||||
inline PropertyIdSetIterator begin() const;
|
||||
inline PropertyIdSetIterator end() const;
|
||||
|
||||
// Erases the property id represented by a valid iterator. Invalidates any previous iterators.
|
||||
// @return A new valid iterator pointing to the next element or end().
|
||||
inline PropertyIdSetIterator erase( const PropertyIdSetIterator& it );
|
||||
|
||||
friend class PropertyIdSetIterator;
|
||||
};
|
||||
|
||||
class EE_API PropertyIdSetIterator {
|
||||
public:
|
||||
using CustomIdsIt = UnorderedSet<Uint32>::const_iterator;
|
||||
PropertyIdSetIterator() : container( nullptr ), bitIndex( 0 ) {}
|
||||
|
||||
PropertyIdSetIterator() : container( nullptr ), custom_ids_iterator() {}
|
||||
PropertyIdSetIterator( const PropertyIdSet* container, CustomIdsIt custom_ids_iterator ) :
|
||||
container( container ), custom_ids_iterator( custom_ids_iterator ) {}
|
||||
explicit PropertyIdSetIterator( const PropertyIdSet* container, std::size_t bitIndex ) :
|
||||
container( container ), bitIndex( bitIndex ) {}
|
||||
|
||||
PropertyIdSetIterator& operator++() {
|
||||
++custom_ids_iterator;
|
||||
if ( container ) {
|
||||
std::size_t next = detail::bitsetFindNext( container->mBits, bitIndex );
|
||||
bitIndex = ( next == container->mBits.size() ) ? container->mBits.size() : next;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==( const PropertyIdSetIterator& other ) const {
|
||||
return container == other.container && custom_ids_iterator == other.custom_ids_iterator;
|
||||
return container == other.container && bitIndex == other.bitIndex;
|
||||
}
|
||||
|
||||
bool operator!=( const PropertyIdSetIterator& other ) const { return !( *this == other ); }
|
||||
|
||||
Uint32 operator*() const { return *custom_ids_iterator; }
|
||||
PropertyId operator*() const { return static_cast<PropertyId>( bitIndex ); }
|
||||
|
||||
private:
|
||||
const PropertyIdSet* container;
|
||||
CustomIdsIt custom_ids_iterator;
|
||||
std::size_t bitIndex;
|
||||
friend PropertyIdSetIterator PropertyIdSet::erase( const PropertyIdSetIterator& );
|
||||
};
|
||||
|
||||
PropertyIdSetIterator PropertyIdSet::begin() const {
|
||||
return PropertyIdSetIterator( this, mIds.begin() );
|
||||
const std::size_t first = detail::bitsetFindFirst( mBits );
|
||||
const std::size_t index = ( first == mBits.size() ) ? mBits.size() : first;
|
||||
return PropertyIdSetIterator( this, index );
|
||||
}
|
||||
|
||||
PropertyIdSetIterator PropertyIdSet::end() const {
|
||||
return PropertyIdSetIterator( this, mIds.end() );
|
||||
return PropertyIdSetIterator( this, mBits.size() );
|
||||
}
|
||||
|
||||
PropertyIdSetIterator PropertyIdSet::erase( const PropertyIdSetIterator& it_in ) {
|
||||
PropertyIdSetIterator it = it_in;
|
||||
it.custom_ids_iterator = mIds.erase( it.custom_ids_iterator );
|
||||
if ( it.container == this && it.bitIndex < mBits.size() ) {
|
||||
mBits.reset( it.bitIndex );
|
||||
++it;
|
||||
}
|
||||
return it;
|
||||
}
|
||||
|
||||
static_assert( sizeof( PropertyIdSet ) == 64, "PropertyIdSet must be a fixed 64-byte bitset" );
|
||||
|
||||
}}} // namespace EE::UI::CSS
|
||||
|
||||
#endif // EE_UI_CSS_PROPERTYIDSET_HPP
|
||||
|
||||
@@ -2,8 +2,12 @@
|
||||
#define EE_UI_CSS_PROPERTYSPECIFICATION_HPP
|
||||
|
||||
#include <eepp/system/singleton.hpp>
|
||||
#include <eepp/ui/css/idnamemap.hpp>
|
||||
#include <eepp/ui/css/propertydefinition.hpp>
|
||||
#include <eepp/ui/css/propertyidset.hpp>
|
||||
#include <eepp/ui/css/shorthanddefinition.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace EE { namespace UI { namespace CSS {
|
||||
|
||||
@@ -12,37 +16,53 @@ class EE_API PropertySpecification {
|
||||
public:
|
||||
~PropertySpecification();
|
||||
|
||||
PropertyDefinition& registerProperty( const std::string& propertyVame,
|
||||
PropertyDefinition& registerProperty( PropertyId id, const std::string& propertyName,
|
||||
const std::string& defaultValue, bool inherited );
|
||||
|
||||
PropertyDefinition* registerProperty( const std::string& propertyName,
|
||||
const std::string& defaultValue, bool inherited );
|
||||
|
||||
const PropertyDefinition* getProperty( const PropertyId& id ) const;
|
||||
|
||||
const PropertyDefinition* getProperty( const Uint32& id ) const;
|
||||
const PropertyDefinition* getProperty( const char* name ) const;
|
||||
|
||||
const PropertyDefinition* getProperty( std::string_view name ) const;
|
||||
|
||||
const PropertyDefinition* getProperty( const std::string& name ) const;
|
||||
|
||||
ShorthandDefinition& registerShorthand( const std::string& name,
|
||||
ShorthandDefinition& registerShorthand( ShorthandId id, const std::string& name,
|
||||
const std::vector<std::string>& properties,
|
||||
const std::string& shorthandParserName );
|
||||
|
||||
const ShorthandDefinition* getShorthand( const String::HashType& id ) const;
|
||||
ShorthandDefinition* registerShorthand( const std::string& name,
|
||||
const std::vector<std::string>& properties,
|
||||
const std::string& shorthandParserName );
|
||||
|
||||
const ShorthandDefinition* getShorthand( const ShorthandId& id ) const;
|
||||
|
||||
const ShorthandDefinition* getShorthand( const std::string& name ) const;
|
||||
|
||||
bool isShorthand( const std::string& name ) const;
|
||||
|
||||
bool isShorthand( const Uint32& id ) const;
|
||||
const PropertyIdSet& getInheritableProperties() const;
|
||||
|
||||
const SmallVector<PropertyId>& getInheritableProperties() const;
|
||||
void finalizeBuiltins();
|
||||
|
||||
protected:
|
||||
friend class PropertyDefinition;
|
||||
friend class ShorthandDefinition;
|
||||
|
||||
std::unordered_map<Uint32, std::shared_ptr<PropertyDefinition>> mProperties;
|
||||
std::unordered_map<Uint32, std::shared_ptr<ShorthandDefinition>> mShorthands;
|
||||
SmallVector<PropertyId> mInheritableProperties;
|
||||
IdNameMap<PropertyId, 512> mPropertyIds;
|
||||
IdNameMap<ShorthandId, 255> mShorthandIds;
|
||||
std::vector<std::shared_ptr<PropertyDefinition>> mPropertiesById;
|
||||
std::vector<std::shared_ptr<ShorthandDefinition>> mShorthandsById;
|
||||
PropertyIdSet mInheritableProperties;
|
||||
|
||||
const PropertyDefinition* addPropertyAlias( Uint32 aliasId, const PropertyDefinition* propDef );
|
||||
const PropertyDefinition* addPropertyAlias( const std::string& alias,
|
||||
const PropertyDefinition* propDef );
|
||||
|
||||
const ShorthandDefinition* addShorthandAlias( const std::string& alias,
|
||||
const ShorthandDefinition* shorthandDef );
|
||||
};
|
||||
|
||||
}}} // namespace EE::UI::CSS
|
||||
|
||||
@@ -3,60 +3,31 @@
|
||||
|
||||
#include <eepp/config.hpp>
|
||||
#include <eepp/core/string.hpp>
|
||||
#include <eepp/ui/css/propertyids.hpp>
|
||||
#include <eepp/ui/css/stylesheetproperty.hpp>
|
||||
#include <functional>
|
||||
|
||||
namespace EE { namespace UI { namespace CSS {
|
||||
|
||||
enum class ShorthandId : Uint32 {
|
||||
Margin = String::hash( "margin" ),
|
||||
Padding = String::hash( "padding" ),
|
||||
Transition = String::hash( "transition" ),
|
||||
Background = String::hash( "background" ),
|
||||
Foreground = String::hash( "foreground" ),
|
||||
BackgroundPosition = String::hash( "background-position" ),
|
||||
ForegroundPosition = String::hash( "foreground-position" ),
|
||||
LayoutMargin = String::hash( "layout-margin" ),
|
||||
LayoutMarginUnderscore = String::hash( "layout_margin" ),
|
||||
RotationOriginPoint = String::hash( "rotation-origin-point" ),
|
||||
ScaleOriginPoint = String::hash( "scale-origin-point" ),
|
||||
BorderColor = String::hash( "border-color" ),
|
||||
BorderWidth = String::hash( "border-width" ),
|
||||
BorderRadius = String::hash( "border-radius" ),
|
||||
MinSize = String::hash( "min-size" ),
|
||||
MaxSize = String::hash( "max-size" ),
|
||||
ListStye = String::hash( "list-style" ),
|
||||
Font = String::hash( "font" ),
|
||||
VerticalAlign = String::hash( "vertical-align" ),
|
||||
BoxMargin = String::hash( "box-margin" ),
|
||||
ForegroundRadius = String::hash( "foreground-radius" ),
|
||||
RotateOriginPoint = String::hash( "rotate-origin-point" ),
|
||||
Border = String::hash( "border" ),
|
||||
TextShadow = String::hash( "text-shadow" ),
|
||||
HintShadow = String::hash( "hint-shadow" ),
|
||||
BorderLeft = String::hash( "border-left" ),
|
||||
BorderRight = String::hash( "border-right" ),
|
||||
BorderTop = String::hash( "border-top" ),
|
||||
BorderBottom = String::hash( "border-bottom" ),
|
||||
};
|
||||
|
||||
typedef std::function<std::vector<StyleSheetProperty>( const ShorthandDefinition* shorthand,
|
||||
std::string value )>
|
||||
ShorthandParserFunc;
|
||||
|
||||
class EE_API ShorthandDefinition {
|
||||
public:
|
||||
static ShorthandDefinition* New( const std::string& name,
|
||||
static ShorthandDefinition* New( ShorthandId shorthandId, const std::string& name,
|
||||
const std::vector<std::string>& properties,
|
||||
const std::string& shorthandParserName );
|
||||
|
||||
ShorthandDefinition( const std::string& name, const std::vector<std::string>& properties,
|
||||
ShorthandDefinition( ShorthandId shorthandId, const std::string& name,
|
||||
const std::vector<std::string>& properties,
|
||||
const std::string& shorthandFuncName );
|
||||
|
||||
std::vector<StyleSheetProperty> parse( std::string value ) const;
|
||||
|
||||
const std::string& getName() const;
|
||||
|
||||
/** @brief Returns the canonical shorthand-name hash, not the dense ShorthandId. */
|
||||
const String::HashType& getId() const;
|
||||
|
||||
ShorthandDefinition& addAlias( const std::string& alias );
|
||||
@@ -69,6 +40,7 @@ class EE_API ShorthandDefinition {
|
||||
|
||||
bool isDefinition( const String::HashType& id ) const;
|
||||
|
||||
/** @brief Returns the dense shorthand identity used for lookup and dispatch. */
|
||||
ShorthandId getShorthandId() const;
|
||||
|
||||
const std::vector<std::string>& getProperties() const;
|
||||
@@ -77,6 +49,7 @@ class EE_API ShorthandDefinition {
|
||||
std::string mName;
|
||||
std::string mFuncName;
|
||||
String::HashType mId;
|
||||
ShorthandId mShorthandId;
|
||||
std::vector<std::string> mAliases;
|
||||
std::vector<String::HashType> mAliasesHash;
|
||||
std::vector<std::string> mProperties;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <eepp/math/rect.hpp>
|
||||
#include <eepp/system/color.hpp>
|
||||
#include <eepp/system/time.hpp>
|
||||
#include <eepp/ui/css/propertyids.hpp>
|
||||
#include <eepp/ui/css/stylesheetlength.hpp>
|
||||
#include <string>
|
||||
|
||||
@@ -46,10 +47,23 @@ class EE_API StyleSheetProperty {
|
||||
const Int64& specificity, bool isVolatile = false,
|
||||
const Uint32& index = 0 );
|
||||
|
||||
/**
|
||||
* @brief Returns the stable name hash used as the key in StyleSheetProperties maps.
|
||||
*
|
||||
* This is not a dense PropertyId or ShorthandId. Unknown and data-* properties
|
||||
* also return their own name hash here.
|
||||
*/
|
||||
Uint32 getId() const;
|
||||
|
||||
/** @brief Returns the dense longhand identity, or PropertyId::Invalid. */
|
||||
PropertyId getPropertyId() const;
|
||||
|
||||
/** @brief Returns the dense shorthand identity, or ShorthandId::Invalid. */
|
||||
ShorthandId getShorthandId() const;
|
||||
|
||||
const std::string& getName() const;
|
||||
|
||||
/** @brief Returns the stable hash of getName(); this is not a dense ID. */
|
||||
const String::HashType& getNameHash() const;
|
||||
|
||||
const std::string& getValue() const;
|
||||
@@ -192,18 +206,18 @@ class EE_API StyleSheetProperty {
|
||||
|
||||
protected:
|
||||
std::string mName;
|
||||
String::HashType mNameHash;
|
||||
String::HashType mNameHash{ 0 };
|
||||
std::string mValue;
|
||||
String::HashType mValueHash;
|
||||
Int64 mSpecificity;
|
||||
Uint32 mIndex;
|
||||
String::HashType mValueHash{ 0 };
|
||||
Int64 mSpecificity{ 0 };
|
||||
Uint32 mIndex{ 0 };
|
||||
bool mVolatile : 1 { false };
|
||||
bool mImportant : 1 { false };
|
||||
bool mIsVarValue : 1 { false };
|
||||
bool mIsLightDarkValue : 1 { false };
|
||||
bool mCachedProperty : 1 { false };
|
||||
const PropertyDefinition* mPropertyDefinition;
|
||||
const ShorthandDefinition* mShorthandDefinition;
|
||||
const PropertyDefinition* mPropertyDefinition{ nullptr };
|
||||
const ShorthandDefinition* mShorthandDefinition{ nullptr };
|
||||
std::vector<StyleSheetProperty> mIndexedProperty;
|
||||
std::vector<VariableFunctionCache> mVarCache;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <eepp/system/singleton.hpp>
|
||||
#include <eepp/ui/css/drawableimageparser.hpp>
|
||||
#include <eepp/ui/css/propertydefinition.hpp>
|
||||
#include <eepp/ui/css/propertyidset.hpp>
|
||||
#include <eepp/ui/css/shorthanddefinition.hpp>
|
||||
#include <functional>
|
||||
|
||||
@@ -37,27 +38,34 @@ class EE_API StyleSheetSpecification {
|
||||
|
||||
~StyleSheetSpecification();
|
||||
|
||||
PropertyDefinition& registerProperty( const std::string& propertyVame,
|
||||
PropertyDefinition& registerProperty( PropertyId id, const std::string& propertyName,
|
||||
const std::string& defaultValue, bool inherited = false );
|
||||
|
||||
PropertyDefinition* registerProperty( const std::string& propertyName,
|
||||
const std::string& defaultValue, bool inherited = false );
|
||||
|
||||
const PropertyDefinition* getProperty( const PropertyId& id ) const;
|
||||
|
||||
const PropertyDefinition* getProperty( const Uint32& id ) const;
|
||||
const PropertyDefinition* getProperty( const char* name ) const;
|
||||
|
||||
const PropertyDefinition* getProperty( std::string_view name ) const;
|
||||
|
||||
const PropertyDefinition* getProperty( const std::string& name ) const;
|
||||
|
||||
const SmallVector<CSS::PropertyId>& getInheritableProperties() const;
|
||||
const PropertyIdSet& getInheritableProperties() const;
|
||||
|
||||
ShorthandDefinition& registerShorthand( const std::string& name,
|
||||
ShorthandDefinition& registerShorthand( ShorthandId id, const std::string& name,
|
||||
const std::vector<std::string>& properties,
|
||||
const std::string& shorthandFuncName );
|
||||
|
||||
const ShorthandDefinition* getShorthand( const Uint32& id ) const;
|
||||
ShorthandDefinition* registerShorthand( const std::string& name,
|
||||
const std::vector<std::string>& properties,
|
||||
const std::string& shorthandFuncName );
|
||||
|
||||
const ShorthandDefinition* getShorthand( const ShorthandId& id ) const;
|
||||
|
||||
const ShorthandDefinition* getShorthand( const std::string& name ) const;
|
||||
|
||||
bool isShorthand( const Uint32& id ) const;
|
||||
|
||||
bool isShorthand( const std::string& name ) const;
|
||||
|
||||
void registerNodeSelector( const std::string& name, StyleSheetNodeSelector nodeSelector );
|
||||
@@ -82,6 +90,8 @@ class EE_API StyleSheetSpecification {
|
||||
void registerDefaultProperties();
|
||||
|
||||
void registerDefaultNodeSelectors();
|
||||
|
||||
void validateBuiltinRegistrations();
|
||||
};
|
||||
|
||||
}}} // namespace EE::UI::CSS
|
||||
|
||||
@@ -29,11 +29,13 @@ class EE_API StyleSheetStyle {
|
||||
|
||||
const StyleSheetVariables& getVariables() const;
|
||||
|
||||
StyleSheetProperty* getPropertyById( const PropertyId& id );
|
||||
|
||||
const StyleSheetProperty* getPropertyById( const PropertyId& id ) const;
|
||||
|
||||
const StyleSheetProperty* getPropertyByDefinition( const PropertyDefinition* def ) const;
|
||||
|
||||
StyleSheetProperty* getPropertyById( const Uint32& id );
|
||||
StyleSheetProperty* getPropertyByNameHash( const String::HashType& id );
|
||||
|
||||
void setProperty( const StyleSheetProperty& property );
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ class CSSPropertiesModel final : public Model {
|
||||
mWidget = widget;
|
||||
mData = widget ? widget->getPropertiesImplemented() : std::vector<PropertyId>();
|
||||
for ( const auto& prop : mData ) {
|
||||
const auto* def = StyleSheetSpecification::instance()->getProperty( (Uint32)prop );
|
||||
const auto* def = StyleSheetSpecification::instance()->getProperty( prop );
|
||||
if ( !def )
|
||||
continue;
|
||||
mProps[prop] = def;
|
||||
|
||||
@@ -75,8 +75,14 @@ class EE_API UIHTMLImage : public UIHTMLWidget {
|
||||
|
||||
virtual void onDisplayChange();
|
||||
|
||||
virtual void onAttributesTransactionEnd();
|
||||
|
||||
void autoSizeImage();
|
||||
|
||||
void reconcileStyleSize();
|
||||
|
||||
bool hasUnresolvedPercentageSize() const;
|
||||
|
||||
void calcDestSize();
|
||||
|
||||
void clearDrawable();
|
||||
@@ -95,6 +101,7 @@ class EE_API UIHTMLImage : public UIHTMLWidget {
|
||||
DrawableResourceConnection mResourceChangeConnection;
|
||||
Uint32 mSpriteChangeCb{ 0 };
|
||||
bool mDeferLoad{ false };
|
||||
bool mNeedsStyleSizeReconciliation{ false };
|
||||
std::shared_ptr<std::atomic<bool>> mAsyncImageAlive;
|
||||
Uint64 mRemoteImageLoadId{ 0 };
|
||||
std::string mAlt;
|
||||
|
||||
@@ -37,7 +37,8 @@ class EE_API UIStyle : public UIState {
|
||||
|
||||
void onStateChange();
|
||||
|
||||
const CSS::StyleSheetProperty* getStatelessStyleSheetProperty( const Uint32& propertyId ) const;
|
||||
const CSS::StyleSheetProperty*
|
||||
getStatelessStyleSheetProperty( const CSS::PropertyId& propertyId ) const;
|
||||
|
||||
void setStyleSheetProperties( const CSS::StyleSheetProperties& properties );
|
||||
|
||||
@@ -75,7 +76,7 @@ class EE_API UIStyle : public UIState {
|
||||
|
||||
UnorderedSet<UIWidget*>& getStructurallyVolatileChildren();
|
||||
|
||||
const CSS::StyleSheetProperty* getProperty( const CSS::PropertyId& id );
|
||||
const CSS::StyleSheetProperty* getProperty( const CSS::PropertyId& id ) const;
|
||||
|
||||
bool hasProperty( const CSS::PropertyId& propertyId ) const;
|
||||
|
||||
@@ -104,7 +105,6 @@ class EE_API UIStyle : public UIState {
|
||||
UnorderedSet<UIWidget*> mRelatedWidgets;
|
||||
UnorderedSet<UIWidget*> mSubscribedWidgets;
|
||||
UnorderedSet<UIWidget*> mStructurallyVolatileChildren;
|
||||
std::optional<CSS::PropertyIdSet> mChangedProperties;
|
||||
Uint32 mStateDepthCounter{ 0 };
|
||||
Uint64 mLoadedVersion{ 0 };
|
||||
const CSS::StyleSheet* mLoadedStyleSheet{ nullptr };
|
||||
@@ -149,10 +149,10 @@ class EE_API UIStyle : public UIState {
|
||||
void removeAnimation( const CSS::PropertyDefinition* propertyDefinition,
|
||||
const Uint32& propertyIndex );
|
||||
|
||||
CSS::StyleSheetProperty* getLocalProperty( Uint32 propId );
|
||||
CSS::StyleSheetProperty* getLocalProperty( CSS::PropertyId propId );
|
||||
|
||||
CSS::StyleSheetProperty*
|
||||
getResolvedLocalProperty( Uint32 propId,
|
||||
getResolvedLocalProperty( CSS::PropertyId propId,
|
||||
std::optional<CSS::StyleSheetProperty>& resolvedProperty );
|
||||
|
||||
void addStructurallyVolatileWidgetFromParent();
|
||||
|
||||
@@ -1654,6 +1654,21 @@ class EE_API UIWidget : public UINode {
|
||||
*/
|
||||
virtual void onSizePolicyChange();
|
||||
|
||||
/**
|
||||
* @brief Called when the outermost attributes transaction ends.
|
||||
*
|
||||
* Invoked from endAttributesTransaction() after the transaction count reaches
|
||||
* zero but before the accumulated layout notifications are emitted. Property
|
||||
* setters run immediately even inside a transaction, so interdependent
|
||||
* properties can be observed in a partially applied state mid-loop. This hook
|
||||
* lets derived widgets perform a final-state reconciliation once the complete
|
||||
* style is applied, making the resulting geometry independent of the setter
|
||||
* application order.
|
||||
*/
|
||||
virtual void onAttributesTransactionEnd();
|
||||
|
||||
bool isInAttributesTransaction() const { return mAttributesTransactionCount > 0; }
|
||||
|
||||
/**
|
||||
* @brief Handles auto-size events.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user