فهرست منبع

:sparkles: Imported CSSFragment from MaterialFX rewrite branch

Alessadro Parisi 2 سال پیش
والد
کامیت
42b0b7b330
1فایلهای تغییر یافته به همراه228 افزوده شده و 0 حذف شده
  1. 228 0
      materialfx/src/main/java/io/github/palexdev/materialfx/css/CSSFragment.java

+ 228 - 0
materialfx/src/main/java/io/github/palexdev/materialfx/css/CSSFragment.java

@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2023 Parisi Alessandro - alessandro.parisi406@gmail.com
+ * This file is part of MaterialFX (https://github.com/palexdev/MaterialFX)
+ *
+ * MaterialFX is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * MaterialFX is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with MaterialFX. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package io.github.palexdev.materialfx.css;
+
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+
+import java.util.Base64;
+import java.util.Objects;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * Allows to build CSS stylesheets by code and apply them on any {@link Parent}.
+ */
+public class CSSFragment {
+	//================================================================================
+	// Properties
+	//================================================================================
+	private static final Base64.Encoder enc = Base64.getEncoder();
+	private final String css;
+	private String converted;
+
+	public static final String DATA_URI_PREFIX = "data:base64,";
+
+	//================================================================================
+	// Constructors
+	//================================================================================
+	public CSSFragment(String css) {
+		this.css = css;
+	}
+
+	//================================================================================
+	// Static Methods
+	//================================================================================
+
+	/**
+	 * Applies the given CSS to the given {@link Parent}
+	 *
+	 * @see #applyOn(Parent)
+	 */
+	public static void applyOn(String css, Parent parent) {
+		CSSFragment f = new CSSFragment(css);
+		f.applyOn(parent);
+	}
+
+	//================================================================================
+	// Methods
+	//================================================================================
+
+	/**
+	 * Converts a CSS string to a data uri that can be used by JavaFX nodes to parse styles.
+	 * <p>
+	 * Subsequent calls to this will be faster as the converted CSS is cached.
+	 *
+	 * @see <a href="https://en.wikipedia.org/wiki/Data_URI_scheme">Data URI Scheme</a>
+	 */
+	public String toDataUri() {
+		if (converted == null) {
+			converted = DATA_URI_PREFIX + new String(enc.encode(css.getBytes(UTF_8)), UTF_8);
+		}
+		return converted;
+	}
+
+	/**
+	 * If this CSS fragment has not been applied yet to the given {@link Parent}, applies it
+	 * using {@link Parent#getStylesheets()}
+	 *
+	 * @see #isAppliedOn(Parent)
+	 */
+	public void applyOn(Parent parent) {
+		if (!isAppliedOn(parent))
+			parent.getStylesheets().add(toDataUri());
+	}
+
+	/**
+	 * If this CSS fragment has not been applied yet to the given {@link Scene}, applies it
+	 * using {@link Scene#getStylesheets()}.
+	 *
+	 * @see #isAppliedOn(Scene)
+	 */
+	public void applyOn(Scene scene) {
+		if (!isAppliedOn(scene))
+			scene.getStylesheets().add(toDataUri());
+	}
+
+	/**
+	 * Checks whether this CSS Fragment has already been applied to the given {@link Parent}
+	 * by checking if its stylesheets list contains this (converted to a Data URI).
+	 */
+	public boolean isAppliedOn(Parent parent) {
+		return parent.getStylesheets().contains(toDataUri());
+	}
+
+	/**
+	 * Checks whether this CSS Fragment has already been applied to the given {@link Scene}
+	 * by checking if its stylesheets list contains this (converted to a Data URI).
+	 */
+	public boolean isAppliedOn(Scene scene) {
+		return scene.getStylesheets().contains(toDataUri());
+	}
+
+	//================================================================================
+	// Overridden Methods
+	//================================================================================
+
+	@Override
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (o == null || getClass() != o.getClass()) return false;
+		CSSFragment that = (CSSFragment) o;
+		return css.equals(that.css);
+	}
+
+	@Override
+	public int hashCode() {
+		return Objects.hash(css);
+	}
+
+	@Override
+	public String toString() {
+		return css;
+	}
+
+	//================================================================================
+	// Builder
+	//================================================================================
+
+	/**
+	 * Allows building {@code CSSFragments} with fluent API.
+	 * <p></p>
+	 * Usage example:
+	 * <pre>
+	 * {@code
+	 * Parent p = ...;
+	 * CssFragment.Builder.build()
+	 *     .addSelector("aSelector")
+	 *     .addStyle("-fx-background-color: red")
+	 *     .addStyle("-fx-background-radius: 10px")
+	 *     .closeSelector()
+	 *     .addSelector("aSelector:hover")
+	 *     .addStyle("-fx-background-color: orange")
+	 *     .addStyle("-fx-border-color: lightgray")
+	 *     .closeSelector()
+	 *     .applyOn(p);
+	 * }
+	 * </pre>
+	 */
+	public static class Builder {
+		private final StringBuilder sb = new StringBuilder();
+
+		public static Builder build() {
+			return new Builder();
+		}
+
+		/**
+		 * Use this to open a block for an element with its selector.
+		 * It's not needed to add the ending '{\n' as it is automatically added.
+		 * <p></p>
+		 * Once you finish the styling block for this element you must call {@link #closeSelector()}
+		 */
+		public Builder addSelector(String selector) {
+			sb.append(selector).append("{\n");
+			return this;
+		}
+
+		/**
+		 * Must always be called after {@link #addSelector(String)} to close the styling block for an element.
+		 */
+		public Builder closeSelector() {
+			sb.append("}\n\n");
+			return this;
+		}
+
+		/**
+		 * Adds the given style to the fragment.
+		 * It's not needed to add the ending ';\n' as it is automatically added.
+		 */
+		public Builder addStyle(String style) {
+			sb.append(style).append(";\n");
+			return this;
+		}
+
+		/**
+		 * Converts the built string to a {@link CSSFragment}.
+		 */
+		public CSSFragment toCSS() {
+			if (sb.length() == 0) throw new IllegalStateException("No styles set");
+			return new CSSFragment(sb.toString());
+		}
+
+		/**
+		 * Applies the created {@link CSSFragment} on the given {@link Parent}.
+		 *
+		 * @see #toCSS()
+		 * @see CSSFragment#applyOn(Parent)
+		 */
+		public void applyOn(Parent parent) {
+			toCSS().applyOn(parent);
+		}
+
+		/**
+		 * Applies the created {@link CSSFragment} on the given {@link Scene}.
+		 *
+		 * @see #toCSS()
+		 * @see CSSFragment#applyOn(Scene)
+		 */
+		public void applyOn(Scene scene) {
+			toCSS().applyOn(scene);
+		}
+	}
+}