Home » Eclipse Projects » Standard Widget Toolkit (SWT) » Trying to theme SWT (CSS?)(Want to create a dark mode look for my SWT application)
|
Re: Trying to theme SWT (CSS?) [message #1822100 is a reply to message #1821946] |
Thu, 27 February 2020 09:42 |
Missing name Mising name Messages: 43 Registered: July 2011 |
Member |
|
|
I also need standalone swt css styling.
I fetched some jars from eclipse plugin directory and tried with CSSSWTEngineImpl class but no luck.
I know that usually this is used with e4 RCP.
But I'd like to use this function with standalone SWT/JFace app.
The following is the code I tried. (usual black label appears)
import java.io.IOException;
import java.io.StringReader;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.core.runtime.spi.IRegistryProvider;
import org.eclipse.e4.ui.css.core.engine.CSSEngine;
import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler;
import org.eclipse.e4.ui.css.swt.engine.CSSSWTEngineImpl;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
public class _CSSTest {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell();
shell.setLayout(new GridLayout());
try {
RegistryFactory.setDefaultRegistryProvider(new IRegistryProvider() {
final IExtensionRegistry r = RegistryFactory.createRegistry(null, null, null);
@Override
public IExtensionRegistry getRegistry() {
return r;
}
});
} catch (CoreException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
Label label = new Label(shell, SWT.LEAD);
label.setText("Hello world!");
label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
CSSEngine engine = new CSSSWTEngineImpl(display);
try {
engine.parseStyleSheet(new StringReader("Label { color: blue; }"));
} catch (IOException e1) {
e1.printStackTrace();
}
engine.setErrorHandler(new CSSErrorHandler() {
public void error(Exception e) {
e.printStackTrace();
}
});
// applying styles to the child nodes means that the engine
// should recurse downwards, in this example, the engine
// should style the children of the Shell
engine.applyStyles(shell, /* applyStylesToChildNodes */ true);
shell.setSize(400, 300);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
[Updated on: Thu, 27 February 2020 09:42] Report message to a moderator
|
|
| |
Re: Trying to theme SWT (CSS?) [message #1822125 is a reply to message #1822114] |
Thu, 27 February 2020 16:04 |
Missing name Mising name Messages: 43 Registered: July 2011 |
Member |
|
|
Now it seems working.
I had to manually set ElementProvider and PropertyHandler.
This page might have some information about handlers.
https://github.com/eclipse/eclipse.platform.ui/blob/master/bundles/org.eclipse.e4.ui.css.swt/plugin.xml
The following code only works for background-color property.
Jars I'm using:
SWT
swt-win64.jar
JFace
com.ibm.icu_64.2.0.v20190507-1337.jar
org.eclipse.core.commands_3.9.400.v20190516-1358.jar
org.eclipse.core.jobs_3.10.400.v20190506-1457.jar
org.eclipse.core.runtime_3.15.300.v20190508-0543.jar
org.eclipse.equinox.common_3.10.400.v20190516-1504.jar
org.eclipse.equinox.registry_3.8.400.v20190516-1504.jar
org.eclipse.jface_3.16.0.v20190528-0922.jar
org.eclipse.jface.databinding_1.9.0.v20190519-0933.jar
org.eclipse.jface.text_3.15.200.v20190519-2344.jar
org.eclipse.osgi_3.14.0.v20190517-1309.jar
org.eclipse.text_3.8.200.v20190519-2344.jar
org.eclipse.ui.forms_3.8.0.v20190519-1034.jar
org.eclipse.ui.workbench_3.115.0.v20190521-1602.jar
SWT CSS
org.apache.batik.css_1.11.0.v20190515-0436.jar
org.apache.batik.i18n_1.11.0.v20190515-0436.jar
org.apache.batik.util_1.11.0.v20190515-0436.jar
org.eclipse.e4.ui.css.core_0.12.900.v20191106-1716.jar
org.eclipse.e4.ui.css.swt_0.13.700.v20191113-1031.jar
org.eclipse.e4.ui.css.swt.theme_0.12.500.v20191125-1011.jar
org.w3c.css.sac_1.3.1.v200903091627.jar
import java.io.IOException;
import java.io.StringReader;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.core.runtime.spi.IRegistryProvider;
import org.eclipse.e4.ui.css.core.dom.properties.css2.ICSSPropertyBackgroundHandler;
import org.eclipse.e4.ui.css.core.dom.properties.providers.CSSPropertyHandlerSimpleProviderImpl;
import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler;
import org.eclipse.e4.ui.css.swt.dom.SWTElementProvider;
import org.eclipse.e4.ui.css.swt.engine.CSSSWTEngineImpl;
import org.eclipse.e4.ui.css.swt.properties.css2.CSSPropertyBackgroundSWTHandler;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
public class _CSSTest {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell();
shell.setLayout(new GridLayout());
try {
RegistryFactory.setDefaultRegistryProvider(new IRegistryProvider() {
final IExtensionRegistry r = RegistryFactory.createRegistry(null, null, null);
@Override
public IExtensionRegistry getRegistry() {
return r;
}
});
} catch (CoreException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
Label label = new Label(shell, SWT.LEAD);
label.setText("Hello world!");
label.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, true, true));
var engine = new CSSSWTEngineImpl(display);
engine.setElementProvider(new SWTElementProvider());
engine.registerCSSPropertyHandlerProvider(new CSSPropertyHandlerSimpleProviderImpl());
engine.registerCSSPropertyHandler(ICSSPropertyBackgroundHandler.class, CSSPropertyBackgroundSWTHandler.INSTANCE);
try {
engine.parseStyleSheet(new StringReader("Label { background-color: blue; }"));
} catch (IOException e1) {
e1.printStackTrace();
}
engine.setErrorHandler(new CSSErrorHandler() {
public void error(Exception e) {
e.printStackTrace();
}
});
// applying styles to the child nodes means that the engine
// should recurse downwards, in this example, the engine
// should style the children of the Shell
engine.applyStyles(label, /* applyStylesToChildNodes */ true);
shell.setSize(400, 300);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
|
|
|
Re: Trying to theme SWT (CSS?) [message #1822152 is a reply to message #1822125] |
Fri, 28 February 2020 03:41 |
Missing name Mising name Messages: 43 Registered: July 2011 |
Member |
|
|
I struggled a bit, and finally made a working example.
This example downloads plugin.xml from GITHUB, and parse it.
So what you need is just SWT / JFace / e4 CSS Jars in your classpath.
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import org.eclipse.core.internal.registry.ExtensionRegistry;
import org.eclipse.core.runtime.RegistryFactory;
import org.eclipse.core.runtime.spi.RegistryContributor;
import org.eclipse.e4.ui.css.core.engine.CSSErrorHandler;
import org.eclipse.e4.ui.css.core.impl.engine.RegistryCSSPropertyHandlerProvider;
import org.eclipse.e4.ui.css.swt.engine.CSSSWTEngineImpl;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Shell;
public class _SWTStandaloneCSS {
public static void main(String[] args) {
var registry = new ExtensionRegistry(null, null, null);
var dummyContributor = new RegistryContributor("", "", "", "");
registry.addExtensionPoint("org.eclipse.e4.ui.css.core.elementProvider", dummyContributor, true, null, null, null);
registry.addExtensionPoint("org.eclipse.e4.ui.css.core.propertyHandler", dummyContributor, true, null, null, null);
try {
registry.addContribution(pluginXMLStream(), dummyContributor, true, null, null, null);
RegistryFactory.setDefaultRegistryProvider(() -> registry);
} catch (Exception e) {
e.printStackTrace();
}
SWTBoilerplate.show(composite -> {
var engine = new CSSSWTEngineImpl(composite.getDisplay());
initCSSEngine(engine, registry);
var content = createContent(composite);
try {
engine.parseStyleSheet(new StringReader("Label { color : red; background-color: blue; }"));
} catch (IOException e1) {
e1.printStackTrace();
}
engine.applyStyles(composite.getShell(), /* applyStylesToChildNodes */ true);
return content;
});
}
static FileInputStream pluginXMLStream() {
File f = download("https://raw.githubusercontent.com/eclipse/eclipse.platform.ui/master/bundles/org.eclipse.e4.ui.css.swt/plugin.xml", "swt_css_plugin.xml");
try {
return new FileInputStream(f);
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
static File download(String url, String destFilePath) {
var f = new File(destFilePath);
if( f.exists() ) return f;
URL website;
try {
website = new URL(url);
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destFilePath);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
return f;
}
static void initCSSEngine(CSSSWTEngineImpl engine, ExtensionRegistry registry) {
engine.registerCSSPropertyHandlerProvider(new RegistryCSSPropertyHandlerProvider(registry));
engine.setErrorHandler(new CSSErrorHandler() {
public void error(Exception e) {
e.printStackTrace();
}
});
}
static Control createContent(Composite comp) {
Label label = new Label(comp, SWT.LEAD);
label.setText("Hello world!");
return label;
}
}
class SWTBoilerplate {
private final Display display;
private Shell shell;
public SWTBoilerplate() {
if( Display.getCurrent() == null) {
display = new Display();
} else {
display = Display.getCurrent();
}
}
public static void show(Image image) {
SWTBoilerplate app = new SWTBoilerplate();
var com = app.launch();
Label l = new Label(com, SWT.NONE);
l.setImage(image);
app.loop(true);
}
public static void show(Function<Composite, Control> creator) {
SWTBoilerplate app = new SWTBoilerplate();
var com = app.launch();
creator.apply(com);
app.loop(true);
}
public static void show(BiFunction<Composite, Shell, Control> creator) {
SWTBoilerplate app = new SWTBoilerplate();
var com = app.launch();
creator.apply(com, com.getShell());
app.loop(true);
}
public Composite launch() {
return launch(new FillLayout(), SWT.SHELL_TRIM);
}
public Composite launch( Layout layout , int shellStyle) {
shell = new Shell(display, shellStyle);
shell.setLayout(new FillLayout());
shell.setSize(800,600);
Composite comp = new Composite(shell, SWT.None);
comp.setLayout( layout );
return comp;
}
public void loop() {
loop(false);
}
public void loop(boolean pack) {
if( shell == null ) {
shell = Display.getCurrent().getShells()[0];
}
shell.open();
if(pack) shell.pack();
while( !shell.isDisposed() ) {
if( !display.readAndDispatch() ) {
display.sleep();
}
}
display.dispose();
}
public static void nloop() {
new SWTBoilerplate().loop();
}
}
[Updated on: Fri, 28 February 2020 03:47] Report message to a moderator
|
|
| | |
Re: Trying to theme SWT (CSS?) [message #1822161 is a reply to message #1822158] |
Fri, 28 February 2020 10:11 |
Missing name Mising name Messages: 43 Registered: July 2011 |
Member |
|
|
Further, I tested in my SWT app.
But unfortunately some renderers seems to be tied with platform bundle system.
Some advanced Controls such as CTabFolders, produce NPE (because they can't find the bundle).
It seems we need some more tweak to perfectly work with the SWT Standalone Application.
Or we have to try e4 RCP Application instead.
Let me know if you have a better solution.
Thank you.
[Updated on: Fri, 28 February 2020 10:15] Report message to a moderator
|
|
| |
Re: Trying to theme SWT (CSS?) [message #1822178 is a reply to message #1822167] |
Fri, 28 February 2020 19:53 |
Missing name Mising name Messages: 43 Registered: July 2011 |
Member |
|
|
Now I could handle with the NPE of CSSPropertyTabRendererSWTHandler.
Just rewrite CSSPropertyTabRendererSWTHandler in your code.
Replace the corresponding class name in plugin.xml and load this instead of downloading from GITHUB at runtime.
I searched in "moonrise-ui-standalone.css" and the only part which uses bundle system was CTabFolderRenderer.
So the live issue was handled.
import java.lang.reflect.Constructor;
import org.eclipse.e4.ui.css.core.engine.CSSEngine;
import org.eclipse.e4.ui.css.swt.helpers.URI;
import org.eclipse.e4.ui.css.swt.properties.AbstractCSSPropertySWTHandler;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabFolderRenderer;
import org.eclipse.swt.widgets.Control;
import org.w3c.dom.css.CSSPrimitiveValue;
import org.w3c.dom.css.CSSValue;
public class StandaloneCSSPropertyTabRendererSWTHandler extends AbstractCSSPropertySWTHandler {
@Override
protected void applyCSSProperty(Control control, String property, CSSValue value, String pseudo, CSSEngine engine)
throws Exception {
if (!(control instanceof CTabFolder)) {
return;
}
if (value.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) {
if (((CSSPrimitiveValue) value).getPrimitiveType() == CSSPrimitiveValue.CSS_URI) {
String rendURL = ((CSSPrimitiveValue) value).getStringValue();
URI uri = URI.createURI(rendURL);
if (uri.authority().equals("org.eclipse.e4.ui.workbench.renderers.swt")) {
Class<?> targetClass = org.eclipse.e4.ui.workbench.renderers.swt.CTabRendering.class;
// check to see if the folder already has an instance of the same renderer
CTabFolderRenderer renderer = ((CTabFolder) control).getRenderer();
if (renderer != null && renderer.getClass() == targetClass) {
return;
}
Constructor<?> constructor = targetClass.getConstructor(CTabFolder.class);
if (constructor != null) {
Object rend = constructor.newInstance(control);
if (rend != null && rend instanceof CTabFolderRenderer) {
((CTabFolder) control).setRenderer((CTabFolderRenderer) rend);
}
}
// }
} else {
((CTabFolder) control).setRenderer(null);
}
}
}
}
@Override
protected String retrieveCSSProperty(Control control, String property, String pseudo, CSSEngine engine)
throws Exception {
return null;
}
}
[Updated on: Sat, 29 February 2020 02:49] Report message to a moderator
|
|
| | | |
Goto Forum:
Current Time: Tue Nov 12 00:03:59 GMT 2024
Powered by FUDForum. Page generated in 0.04530 seconds
|