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

Icons can't be styled via user agent stylesheet #121

Closed
dlemmermann opened this issue Nov 9, 2020 · 9 comments
Closed

Icons can't be styled via user agent stylesheet #121

dlemmermann opened this issue Nov 9, 2020 · 9 comments
Assignees
Labels
Milestone

Comments

@dlemmermann
Copy link

It seems like it is not possible to style an icon via the "user agent stylesheet" of a custom control (using a skin). When you run the standalone app below you will notice that styling works fine but when you comment out the line getStylesheets().add(IkonliBug.class.getResource("styles.css").toExternalForm()); then only the user agent stylesheet will be used (returned via the getUserAgentStylesheet() method) and styling no longer works.

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Control;
import javafx.scene.control.Skin;
import javafx.scene.control.SkinBase;
import javafx.stage.Stage;
import org.kordamp.ikonli.javafx.FontIcon;
import org.kordamp.ikonli.materialdesign.MaterialDesign;


public class IkonliBugApp extends Application {

    @Override
    public void start(Stage stage) {
        IkonliBug bug = new IkonliBug();
        Scene scene = new Scene(bug);
        stage.setTitle("Ikonli Bug?");
        stage.setScene(scene);
        stage.setWidth(400);
        stage.setHeight(400);
        stage.centerOnScreen();
        stage.show();
    }

    public static void main(String[] args) {
        launch();
    }

    public class IkonliBug extends Control {

        private final FontIcon fontIcon = new FontIcon(MaterialDesign.MDI_UPLOAD);

        public IkonliBug() {
            getStyleClass().add("ikonli-bug");

            /*
             * We need to also add the stylesheet directly as otherwise the styling for the
             * ikonli font icon will not work. Bug in Ikonli?
             */
            getStylesheets().add(IkonliBug.class.getResource("styles.css").toExternalForm());
        }

        public FontIcon getFontIcon() {
            return fontIcon;
        }

        @Override
        protected Skin<?> createDefaultSkin() {
            return new IkonliBugSkin(this);
        }

        @Override
        public String getUserAgentStylesheet() {
            return IkonliBug.class.getResource("styles.css").toExternalForm();
        }

    }

    public class IkonliBugSkin extends SkinBase<IkonliBug> {

        public IkonliBugSkin(IkonliBug view) {
            super(view);
            getChildren().setAll(view.getFontIcon());
        }
    }
}
@dlemmermann
Copy link
Author

dlemmermann commented Nov 9, 2020

The CSS ins styles.css:

.ikonli-font-icon {
    -fx-icon-size: 48px;
    -fx-icon-color: blue;
    -fx-icon-code: mdi-camera;
}

@dlemmermann
Copy link
Author

According to the Javadocs of getUserAgentStylesheet() this should work. We are using this method heavily in ControlsFX, too.

An implementation may specify its own user-agent styles for this Region, and its children, by overriding this method. These styles are used in addition to whatever user-agent stylesheets are in use. This provides a mechanism for third parties to introduce styles for custom controls.

@dlemmermann
Copy link
Author

Any idea, yet, how this can be fixed / should be fixed?

@aalmiray
Copy link
Collaborator

Unfortunately no, I've got no clue why it's not working.

@palexdev
Copy link

palexdev commented Mar 3, 2021

I suspect this to be a JavaFX bug
Lately I'm having this issue a lot in my custom controls and to change the style of a sub component I have to force it by calling getStyesheets().setAll()

Also in the newer JavaFX versions the documentation has been updated to add:

Subclasses overriding this method should not  
assume any particular implementation approach as  
to the number and frequency with which it is called.  
For this reason, attempting any kind of dynamic  
implementation (i.e. returning different user agent stylesheet values)   based on some state change is  
highly discouraged, as there is no guarantee when,  
or even if, this method will be called. Some JavaFX  
CSS implementations may choose to cache this  
response for an indefinite period of time, and   therefore there should be no expectation around  
when this method is called.  

I wonder if that could be the problem, but I'm just guessing

@palexdev
Copy link

palexdev commented Nov 7, 2021

@aalmiray @dlemmermann I finally found the issue and an alternative workaround.

JavaFX' StyleableProperties have a way to specify the origin of the value, see here Docs
If you set the value of a StyleableProperty via code (with a setter) it will set the origin to USER and ignore the USER_AGENT stylesheet.
So basically when you use the constructor you're setting the icon properties via code which then stops the user agent from working.
A workaround is to override the getStyleOrigin() method to always return USER_AGENT.

Here's the same example @dlemmermann provided, but I built a custom version of ikonli that implements such workaround, you can see the difference by switching the dependencies in gradle.
Example

Edit: here's what I mean by overriding getStyleOrigin()
image

@aalmiray
Copy link
Collaborator

aalmiray commented Nov 7, 2021

Thank you @palexdev! This looks promising. Wonder if it would work as low as JavaFX 11, though with recent version of JavaFX (such as 17) still being binary compatible with Java 11 then I might bump Ikonli all the way to JavaFX 17.

@palexdev
Copy link

palexdev commented Nov 7, 2021

Thank you @palexdev! This looks promising. Wonder if it would work as low as JavaFX 11, though with recent version of JavaFX (such as 170 still being binary compatible with Java 11 then I might bump Ikonli all the way to JavaFX 17.

Ah yes, I like to always use the latest releases
I can test it with JDK11 + JFX11 and report back

@aalmiray aalmiray self-assigned this Dec 16, 2021
@aalmiray aalmiray added the Bug label Dec 16, 2021
@aalmiray aalmiray added this to the 12.3.0 milestone Dec 16, 2021
@dlemmermann
Copy link
Author

Thank you guys!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants