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

8267546: Add CSS themes as a first-class concept #511

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
80fa8de
StyleTheme implementation
mstr2 Nov 8, 2022
da9d31e
Removed unrelated code from ThemeBase
mstr2 Nov 9, 2022
173de61
Update PlatformPreferences when dark mode is enabled
mstr2 Nov 10, 2022
1cd4225
Removed unused StylesheetList constructor
mstr2 Nov 11, 2022
bce6a4b
Set initial preferences from QuantumToolkit
mstr2 Nov 22, 2022
9fdb3c2
Added macOS platform preferences implementation
mstr2 Nov 23, 2022
3424597
Javadoc table formatting
mstr2 Nov 23, 2022
a47a35a
Added manual PlatformPreferencesTest
mstr2 Dec 12, 2022
41f32cc
Merge branch 'master' into feature/theming
mstr2 Dec 12, 2022
9eab40f
Refactored win/ThemeSupport
mstr2 Dec 20, 2022
98e3bd7
Improved log formatting in PlatformPreferencesTest
mstr2 Dec 20, 2022
1cc1351
GTK platform preferences implementation
mstr2 Dec 21, 2022
d37d6b7
macOS platform preferences refactoring
mstr2 Dec 22, 2022
4a361d5
Merge branch 'master' into feature/theming
mstr2 Dec 22, 2022
e4f6d39
Application.userAgentStylesheet/styleTheme can be modified on any thread
mstr2 Dec 22, 2022
2dedeea
Remove legacy system colors
mstr2 Dec 22, 2022
444d4c0
Update javadoc-since tags
mstr2 Dec 26, 2022
84598dc
Added manual StyleTheme test
mstr2 Jan 1, 2023
b390f46
Updated copyright headers
mstr2 Jan 4, 2023
1304d25
Added missing newline at end of file
mstr2 Jan 4, 2023
71e6cfc
Platform.Preferences implements ObservableMap
mstr2 Jan 9, 2023
757f7ff
Changed GTK preference keys
mstr2 Jan 9, 2023
1288208
Rename Application.styleTheme to userAgentStyleTheme
mstr2 Jan 21, 2023
27ead34
update javadoc
mstr2 Jan 21, 2023
2757610
update javadoc
mstr2 Jan 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -93,10 +93,8 @@ public StringProperty skinClassNameProperty(Control control) {
}
});

// Ensures that the default application user agent stylesheet is loaded
if (Application.getUserAgentStylesheet() == null) {
PlatformImpl.setDefaultPlatformUserAgentStylesheet();
}
// Ensures that the default theme is loaded
PlatformImpl.ensureDefaultTheme();
}

/**
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -84,10 +84,8 @@ public class PopupControl extends PopupWindow implements Skinnable, Styleable {
public static final double USE_COMPUTED_SIZE = -1;

static {
// Ensures that the default application user agent stylesheet is loaded
if (Application.getUserAgentStylesheet() == null) {
PlatformImpl.setDefaultPlatformUserAgentStylesheet();
}
// Ensures that the default theme is loaded
PlatformImpl.ensureDefaultTheme();
}

/**
Expand Down
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package javafx.scene.control.theme;

import com.sun.javafx.PlatformUtil;
import com.sun.javafx.application.PlatformImpl;
import javafx.application.ConditionalFeature;
import javafx.application.Platform;
import javafx.beans.value.WritableValue;

/**
* {@code Caspian} is a built-in JavaFX theme that shipped as default in JavaFX 2.
*
* @since 21
*/
public class CaspianTheme extends ThemeBase {

private final WritableValue<String> highContrastStylesheet;

/**
* Creates a new instance of the {@code CaspianTheme} class.
*/
public CaspianTheme() {
addLast("com/sun/javafx/scene/control/skin/caspian/caspian.css");

if (PlatformImpl.isSupported(ConditionalFeature.INPUT_TOUCH)) {
addLast("com/sun/javafx/scene/control/skin/caspian/embedded.css");

if (com.sun.javafx.util.Utils.isQVGAScreen()) {
addLast("com/sun/javafx/scene/control/skin/caspian/embedded-qvga.css");
}

if (PlatformUtil.isAndroid()) {
addLast("com/sun/javafx/scene/control/skin/caspian/android.css");
}

if (PlatformUtil.isIOS()) {
addLast("com/sun/javafx/scene/control/skin/caspian/ios.css");
}
}

if (PlatformImpl.isSupported(ConditionalFeature.TWO_LEVEL_FOCUS)) {
addLast("com/sun/javafx/scene/control/skin/caspian/two-level-focus.css");
}

if (PlatformImpl.isSupported(ConditionalFeature.VIRTUAL_KEYBOARD)) {
addLast("com/sun/javafx/scene/control/skin/caspian/fxvk.css");
}

if (!PlatformImpl.isSupported(ConditionalFeature.TRANSPARENT_WINDOW)) {
addLast("com/sun/javafx/scene/control/skin/caspian/caspian-no-transparency.css");
}

highContrastStylesheet = addLast(null);
updateHighContrastTheme();
}

@Override
protected void onPreferencesChanged() {
updateHighContrastTheme();
}

private void updateHighContrastTheme() {
boolean enabled = false;
String overrideThemeName = System.getProperty("com.sun.javafx.highContrastTheme");
if (overrideThemeName != null) {
enabled = true;
}

if (!enabled) {
Platform.Preferences preferences = Platform.getPreferences();
if (preferences.getBoolean("Windows.SPI.HighContrastOn", false)) {
enabled = preferences.getString("Windows.SPI.HighContrastColorScheme") != null;
}
}

if (enabled) {
// caspian has only one high contrast theme, use it regardless of the user or platform theme.
highContrastStylesheet.setValue("com/sun/javafx/scene/control/skin/caspian/highcontrast.css");
} else {
highContrastStylesheet.setValue(null);
}
}

}
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package javafx.scene.control.theme;

import com.sun.javafx.PlatformUtil;
import com.sun.javafx.application.HighContrastScheme;
import com.sun.javafx.application.PlatformImpl;
import javafx.application.ConditionalFeature;
import javafx.application.Platform;
import javafx.beans.value.WritableValue;
import java.util.ResourceBundle;

/**
* {@code Modena} is the default built-in JavaFX theme as of JavaFX 8.
*
* @since 21
*/
public class ModenaTheme extends ThemeBase {

private final WritableValue<String> highContrastStylesheet;

/**
* Creates a new instance of the {@code ModenaTheme} class.
*/
public ModenaTheme() {
addLast("com/sun/javafx/scene/control/skin/modena/modena.css");

if (PlatformImpl.isSupported(ConditionalFeature.INPUT_TOUCH)) {
addLast("com/sun/javafx/scene/control/skin/modena/touch.css");
}

if (PlatformUtil.isEmbedded()) {
addLast("com/sun/javafx/scene/control/skin/modena/modena-embedded-performance.css");
}

if (PlatformUtil.isAndroid()) {
addLast("com/sun/javafx/scene/control/skin/modena/android.css");
}

if (PlatformUtil.isIOS()) {
addLast("com/sun/javafx/scene/control/skin/modena/ios.css");
}

if (PlatformImpl.isSupported(ConditionalFeature.TWO_LEVEL_FOCUS)) {
addLast("com/sun/javafx/scene/control/skin/modena/two-level-focus.css");
}

if (PlatformImpl.isSupported(ConditionalFeature.VIRTUAL_KEYBOARD)) {
addLast("com/sun/javafx/scene/control/skin/caspian/fxvk.css");
}

if (!PlatformImpl.isSupported(ConditionalFeature.TRANSPARENT_WINDOW)) {
addLast("com/sun/javafx/scene/control/skin/modena/modena-no-transparency.css");
}

highContrastStylesheet = addLast(null);
updateHighContrastTheme();
}

@Override
protected void onPreferencesChanged() {
updateHighContrastTheme();
}

private void updateHighContrastTheme() {
String themeName = null;
String overrideThemeName = System.getProperty("com.sun.javafx.highContrastTheme");
if (overrideThemeName != null) {
themeName = overrideThemeName;
}

if (themeName == null) {
Platform.Preferences preferences = Platform.getPreferences();
if (preferences.getBoolean("Windows.SPI.HighContrastOn", false)) {
themeName = preferences.getString("Windows.SPI.HighContrastColorScheme");
}
}

if (themeName != null) {
String stylesheet = switch (themeName.toUpperCase()) {
case "BLACKONWHITE" -> "com/sun/javafx/scene/control/skin/modena/blackOnWhite.css";
case "WHITEONBLACK" -> "com/sun/javafx/scene/control/skin/modena/whiteOnBlack.css";
case "YELLOWONBLACK" -> "com/sun/javafx/scene/control/skin/modena/yellowOnBlack.css";
default -> null;
};

if (stylesheet == null) {
ResourceBundle bundle = ResourceBundle.getBundle("com/sun/glass/ui/win/themes");
String enumValue = HighContrastScheme.fromThemeName(bundle::getString, themeName);

stylesheet = enumValue != null ? switch (HighContrastScheme.valueOf(enumValue)) {
case HIGH_CONTRAST_WHITE -> "com/sun/javafx/scene/control/skin/modena/blackOnWhite.css";
case HIGH_CONTRAST_BLACK -> "com/sun/javafx/scene/control/skin/modena/whiteOnBlack.css";
case HIGH_CONTRAST_1, HIGH_CONTRAST_2 -> "com/sun/javafx/scene/control/skin/modena/yellowOnBlack.css";
} : null;
}

highContrastStylesheet.setValue(stylesheet);
} else {
highContrastStylesheet.setValue(null);
}
}

}