Relative Linking Revisited
Tuesday, February 4, 2025
The Goal
When a link path is relative (meaning it contains double-dot notation), the relativity should be dependent on the caller that is requesting the attribute's value. This means that relative links cannot be pre-resolved. They must be resolved during attribute valuation.
The following is a simple example of a relative link path:
../Fill
If the above link path is used by a base attribute, then its resolution depends on the context of the derivative definitions that inherit the base attribute.
The Issue
The issue is that the derivative definitions appear to be difficult to obtain during attribute valuation.
Consider the following example.
There are two derivative definitions with the following tags:
Main Window/Definition Editor/Set Editor/Editor/Attribute Editors Scroll Area/Vertical Scrollbar
Main Window/Definition Editor/Set Editor/Editor/Sidebar/Definition View/Vertical Scrollbar
Both of these definitions inherit QLayers/qlscrollbar.json::Scroll Bar.
Keep in mind that it would be the definable widgets requesting their attribute values, likely during their paint operations. So, when the actual scroll bars get painted, that begins the attribute valuation process.
Definables are supposed to have attributes as member variables. So, each Vertical Scrollbar widget (not definition) has its own set of attributes (we call these the definable attributes or widget attributes).
Just as there are two scroll bar widgets involved here, they both have their own independent definitions, as mentioned above. However, these definitions simply inherit the same base scroll bar definition. With definition inheritance, derivative definitions use the attributes of their base, they don't copy the attributes. Therefore, both derivative definitions ultimately use the Scroll Bar's attributes (they could override specific attributes, but in this case, neither derivatives do so).
During definition application, there is also a form of definition attribute application. This is because definable attributes apply definition attributes. So, definable attributes maintain a pointer to their associated definition attributes.
The big issue here is that definables will end up applying the base definition attributes, and when their parent is requested, you get the base definition. However, as mentioned in the goal, the context of the derivative definition is required for relative linking.
When one of the Vertical Scrollbar widgets requests a value for its Background Color attribute, LAttribute::as() gets called, specifically with the definable attribute.
The first thing that function does is check if their is an associated definition attribute. Since their should be, LAttribute::as() gets called again with the definition attribute. In this case, the definition attribute happens to be the base attribute from Scroll Bar, the same one used by other scroll bars.
It is both at this point where the relative link path would be discovered, since it is defined by the base attribute, but also, if LAttribute::parent() is called, you would get the base definition instead of the derivative definition.
Now, I understand if I could return the relative link path up to the first as() call, I would be able to call LAttribute::parent() and get the definable widget. And if I call LDefinable::definition(), then I would get the derivative definition that I am seeking.