Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update LookEvent to SkinEvent and Improvment on Selection #16

Merged
merged 1 commit into from
Oct 29, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 60 additions & 30 deletions Chapters/toplo/stylesheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The phases are :
Toplo will add 2 new phases to this list, between the Drawing Validation and Layout phases. These two phases are :

51. **Skin Installer:** Checks if a new skin should be installed on graphic elements. If so, it will recalculate the layout, uninstall the old skin and install the new one.
52. **Skin State Application:** Creates look events based on the state of graphic elements.
52. **Skin State Application:** Creates skin events based on the state of graphic elements.

These two phases are added to a space when an element requests the installation of a new skin for the first time.

Expand All @@ -46,12 +46,12 @@ States are generated by an event handler (`ToSkinStateGenerator`) associated wit
Only elements with this event handler can receive skins.

When a new skin is installed, the skin manager adds an event handler to the graphic element.
This event handler is a `ToStyleSheetSkin`. This event handler manages look events (`ToElementLookEvent`).
This event handler is a `ToStyleSheetSkin`. This event handler manages sinn events (`ToSkinEvent`).
It uses the element's *writers* to update the properties of the element.

Look events are events created during the *SkinStateApplication phase* based on the current state of the graphic element. There are 3 categories of look events: management events (skin installation and uninstallation), intrinsic events (focus/unfocus, checked/unchecked, etc.) and transient events (pressed, drag, hover, etc.).
Skin events are events created during the *SkinStateApplication phase* based on the current state of the graphic element. There are 3 categories of skin events: management events (skin installation and uninstallation), intrinsic events (focus/unfocus, checked/unchecked, etc.) and transient events (pressed, drag, hover, etc.).

Element's *writers* are *ToLookEventListener* and are described in the skin *theme*. They correspond to the set of style rules for the graphic element.
Element's *writers* are *ToSkinEventListener* and are described in the skin *theme*. They correspond to the set of style rules for the graphic element.

There are two ways to install a new skin for a graphic element. It's possible to apply a new theme to all the graphic elements in a space. It's also possible to update an element's *tokens* or *stamps*, in which case the skin of the children's element will also be replaced by an updated version.

Expand Down Expand Up @@ -88,18 +88,18 @@ Selectors can be combined together using different operators. There are 6 differ
* **Parent:** Allows you to apply a selector to the graphic element's parent. It is possible to set a parent depth level.
* **Sibling:** Allows you to apply a selector to graphic elements having the same parent as the graphic element.

All selectors and combinations are interpreted by **ToSelectorInterpreter** each time a theme is installed on a space. If the selector "matches" with one of the graphic elements, the associated writers are installed on the element. By default, only the last writter per editable property and look event is installed for a given graphic element. You can force a rule to be applied using the *supplements* variable.
All selectors and combinations are interpreted by **ToSelectorInterpreter** each time a theme is installed on a space. If the selector "matches" with one of the graphic elements, the associated writers are installed on the element. By default, only the last writter per editable property and skin event is installed for a given graphic element. You can force a rule to be applied using the *supplements* variable.

Writers are `ToLookEventListeners`. They respond to look events. Writers modify the editable properties of each graphic element. Style rules and their associated writers are built by a *scripter* (`TToStyleRuleScripter`). To create a style rule, use the `#select:style:` method, with a selector for the rule as the first argument and a block closure that executes the associated writers as the second argument. The scripter has 8 different methods for creating writers:
Writers are `ToSkinEventListeners`. They respond to skin events. Writers modify the editable properties of each graphic element. Style rules and their associated writers are built by a *scripter* (`TToStyleRuleScripter`). To create a style rule, use the `#select:style:` method, with a selector for the rule as the first argument and a block closure that executes the associated writers as the second argument. The scripter has 8 different methods for creating writers:

* `#do:` - Executes a block with the element selected when the skin is installed as argument.
* `#when:do:` - Executes a block with the selected element as argument for a given look event.
* `#when:do:` - Executes a block with the selected element as argument for a given skin event.
* `#write:with:` - Modifies an editable property with the given value.
* `#write:whitAll:` - Modifies a list of editable properties with the given values.
* `#when:write:with:` - Modifies an editable property with the given value for a given look event.
* `#when:write:with:animation:` - Modifies an editable property with the given value and associated animation for a given look event.
* `#when:write:with:` - Modifies an editable property with the given value for a given skin event.
* `#when:write:with:animation:` - Modifies an editable property with the given value and associated animation for a given skin event.
* `#supplement:with:` - Forces the modification of an editable property with the given value.
* `#when:supplement:with:` - Forces the modification of an editable property with the given value for a given look event.
* `#when:supplement:with:` - Forces the modification of an editable property with the given value for a given skin event.


### Core elements
Expand Down Expand Up @@ -211,11 +211,11 @@ ToButton asTypeSelector
style: [ :sr |
"Background"
sr
when: ToInstallLookEvent
when: ToInstallSkinEvent
write: (self property: #'background-color')
with: [ :e | e tokenValueNamed: #'color-bg-container' ].
sr
when: ToDisabledLookEvent
when: ToDisabledSkinEvent
write: (self property: #'background-color')
with: [ :e | e tokenValueNamed: #'color-bg-container-disabled' ].
]
Expand Down Expand Up @@ -247,7 +247,7 @@ Finally

```smalltalk
self
when: ToDisabledLookEvent
when: ToDisabledSkinEvent
write: (self property: #'text-attributes-with-builder')
with: [ :e |
e textAttributesBuilder foreground:
Expand Down Expand Up @@ -293,8 +293,6 @@ self
]
```



### Style sheet definition

Styles are defined vis `select:style:`messages with multiple arguments.
Expand All @@ -305,25 +303,57 @@ with the following element element selection.
Element selection is managed by `ToElementSelector`.

#### Type selection
Type selector are selection based on the class of the BlElement.
Using the message `asTypeSelector any element class can play this role.
Type selector are selection based on the class of the BlElement.

`ToLabel asTypeSelector` or `ToButton asTypeSelector`
or you can use `type:` as in `ToTypeSelector new type: ToElement`
To create a selection based on the class you can use the message `asTypeSelector any
element class.
For example: `ToLabel asTypeSelector` or `ToButton asTypeSelector`.
You can also create an object `ToTypeSelector`.
For example: `ToTypeSelector new type: ToLabel; yourself`.

By default, the type selector will select the element only if the type is the same as the element's class.
You can set the type selector to select the element if the element's class is also a subclass of the type.
To do it, you simply have to change the `#exact:` value.
For example: `ToTypeSelector new type: ToButton; yourself` will not select a `ToCheckbox` but `ToTypeSelector new type: ToButton; exact: false; yourself` will.

#### Id selection
The selection can also be based on the id of an element.

- element definition as in `ToButton id: #buttonA`
- element query as in `id: #buttonA`
To create a selection based on the id you can use the message `asIdSelector` on a `String`.
For example: `#buttonA asIdSelector` will select `ToButton id: #buttonA`
You can also create an object `ToIdSelector`.
For example: `ToIdSelector new id: #buttonA; yourself`.

#### Stamps selection
The selection can be based on specific stamps attached to an element.

To add a stamp to an element you can use the message `addStamp:` on the element.
For example: `ToButton new addStamp: #'primary'; yourself`.
An element can have multiple stamps.
For example: `ToButton new addStamp: #'primary'; addStamp: #'error'; yourself`.
You can also use `removeStamp:` as well to remove a stamp.

To create a selection based on the stamps you can use the message `asStampSelector` on a `String` or a `Collection`.
If you use the message on a `String`, the element will be selected if it contains a stamp with the same name.
For example: `#primary asStampSelector` will select`ToButton new addStamp: #'primary'; addStamp: #'error'; yourself`.
If you use the message on a `Collection`, the element will be selected if it contains all the stamps.
For example: `{ #primary . #ghost } asStampSelector` will not select `ToButton new addStamp: #'primary'; addStamp: #'error'; yourself`.
You can also create an object `ToStampSelector`.
For example: `ToStampSelector new addAllStamps: { #primary . #ghost }; yourself`.

#### Action selection
The selection can be based on the evaluation of `BlockClosure` with one argument.
The argument will be the elements tested for the selection.
To create a selection based on `BlockClosure` you can use `asActionSelector` on a `BlockClosure`.
For example: `[ :element | element childrenCount > 3 ] asActionSelector` will select all element with more than 3 children.

#### Stamp selection
The selection can be based on specific stamp attached to an element.
You can also create a `ToActionSelector` object.
For example: `ToActionSelector new action: [ :element | element childrenCount > 3 ]; yourself`.

- element definition as in: `ToButton new addStamp: #'primary'.`
- element query as in: `#primary asStampSelector`
#### Universal selection
To select all elements, you can use the `ToUniversalSelector`.
For example: `ToUniversalSelector new`.

You can also use `removeStamp:` as well to change a stamp.

#### Child, parent or sibling selection

Expand Down Expand Up @@ -359,7 +389,7 @@ Style will be passed a Block to define specific style attribute.
- `when:write:with:animation:` associates change to an event and with an animation

The message arguments follow:
- `when:` argument is a look event, part of the list `ToElementLookEvent allSubclasses`
- `when:` argument is a Skin event, part of the list `ToSkinEvent allSubclasses`
- `write:` and `supplement:` argument will get the property to change
- `with:` argument is a block whose parameter is the element that needs to
be changed.
Expand All @@ -375,17 +405,17 @@ backgroundColorAnim := ToPropertyColorTransitionAnimation new
select: self buttonSelector && #primary asStampSelector
style: [
self
when: ToInstallLookEvent
when: ToInstallSkinEvent
write: (self property: #'background-color')
with: [ :e | e tokenValueNamed: #'color-primary' ].
self
when: ToLeavedLookEvent
when: ToLeavedSkinEvent
write: (self property: #'background-color')
with: [ :e | e tokenValueNamed: #'color-primary' ]
animation: backgroundColorAnim.

self
when: ToInstallLookEvent
when: ToInstallSkinEvent
write: (self property: #'border-with-builder')
with: [ :e |
e borderBuilder
Expand Down