eclipse.platform.swt icon indicating copy to clipboard operation
eclipse.platform.swt copied to clipboard

[Win32] Table and Tree use light background, if disabled and EraseItem event is registered

Open tmssngr opened this issue 10 months ago • 2 comments

Describe the bug For a dark theme the background color of a disabled Tree or Table is white.

To Reproduce Run this snippet on Windows and toggle the "enabled" checkbox:

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

/**
 * @author Thomas Singer
 */
public class DarkControlTest {

	private static final Color DARK_GRAY = new Color(32, 32, 32);
	private static final Color LIGHT_GRAY = new Color(200, 200, 200);

	public static void main(String[] args) {
		final Display display = new Display();

		display.addListener(SWT.Skin, event -> {
			if (event.widget instanceof Control control) {
				control.setBackground(DARK_GRAY);
				control.setForeground(LIGHT_GRAY);
				if (control instanceof Table table) {
					table.setHeaderBackground(DARK_GRAY);
					table.setHeaderForeground(LIGHT_GRAY);
				}
				if (control instanceof Tree tree) {
					tree.setHeaderBackground(DARK_GRAY);
					tree.setHeaderForeground(LIGHT_GRAY);
				}
			}
		});

		final Shell shell = new Shell(display);
		shell.setLayout(new GridLayout(2, true));

		final Control table = createTable(shell);
		final Control tree = createTree(shell);

		final Button checkbox = new Button(shell, SWT.CHECK);
		checkbox.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));
		checkbox.setText("enabled");
		checkbox.setSelection(true);
		checkbox.addListener(SWT.Selection, event -> {
			table.setEnabled(checkbox.getSelection());
			tree.setEnabled(checkbox.getSelection());
		});

		shell.setSize(400, 300);
		shell.open();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

		display.dispose();
	}

	private static Table createTable(Composite parent) {
		final Table table = new Table(parent, SWT.BORDER);
		table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		table.setHeaderVisible(true);

		table.addListener(SWT.EraseItem, event -> {
			final Rectangle clientArea = table.getClientArea();
			event.gc.fillRectangle(clientArea.x, event.y, clientArea.width, event.height);

			event.detail &= ~(SWT.FOREGROUND | SWT.BACKGROUND | SWT.HOT | SWT.SELECTED);
		});
		table.addListener(SWT.PaintItem, event -> {
			event.gc.drawText(((Item)event.item).getText(), event.x, event.y);
		});


		final TableColumn column = new TableColumn(table, SWT.LEFT);
		column.setText("Column");
		column.setWidth(150);

		new TableItem(table, SWT.LEFT).setText("Item 1");
		new TableItem(table, SWT.LEFT).setText("Item 2");
		return table;
	}

	private static Tree createTree(Composite parent) {
		final Tree tree = new Tree(parent, SWT.BORDER);
		tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		tree.setHeaderVisible(true);

		tree.addListener(SWT.EraseItem, event -> {
			event.gc.setClipping((Rectangle)null);
			final Rectangle clientArea = tree.getClientArea();
			event.gc.fillRectangle(clientArea.x, event.y, clientArea.width, event.height);

			event.detail &= ~(SWT.FOREGROUND | SWT.BACKGROUND | SWT.HOT | SWT.SELECTED);
		});
		tree.addListener(SWT.PaintItem, event -> {
			event.gc.drawText(((Item)event.item).getText(), event.x, event.y);
		});

		new TreeItem(tree, SWT.LEFT).setText("Item 1");
		new TreeItem(tree, SWT.LEFT).setText("Item 2");
		return tree;
	}
}

Expected behavior In both cases, enabled and disabled, the set background color should be used.

Screenshots enabled: Image

disabled: Image

Environment:

  1. Select the platform(s) on which the behavior is seen:
    • [ ] All OS
    • [x] Windows
    • [ ] Linux
    • [ ] macOS

tmssngr avatar Feb 15 '25 10:02 tmssngr

Hi @tmssngr I tried a slight modification in your program as below

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

/**
 * @author Thomas Singer
 */
public class DarkControlTest {

	private static final Color DARK_GRAY = new Color(32, 32, 32);
	private static final Color LIGHT_GRAY = new Color(200, 200, 200);

	public static void main(String[] args) {
		final Display display = new Display();

		display.addListener(SWT.Skin, event -> {
			if (event.widget instanceof Control control) {
				control.setBackground(DARK_GRAY);
				control.setForeground(LIGHT_GRAY);
				if (control instanceof Table table) {
//					table.setHeaderBackground(DARK_GRAY);
//					table.setHeaderForeground(LIGHT_GRAY);
					System.out.println(table.getBackground().getRGB() + "Before : table.getBackground().getRGB()");
					table.setHeaderBackground(table.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
					table.setHeaderForeground(table.getDisplay().getSystemColor(SWT.COLOR_GRAY));
					table.setBackground(table.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
					table.setForeground(table.getDisplay().getSystemColor(SWT.COLOR_GRAY));
					System.out.println(table.getBackground().getRGB() + "After : table.getBackground().getRGB()");
				}
				if (control instanceof Tree tree) {
//					tree.setHeaderBackground(DARK_GRAY);
//					tree.setHeaderForeground(LIGHT_GRAY);
					System.out.println(tree.getBackground().getRGB()+ "Before : tree.getBackground().getRGB()");
					tree.setHeaderBackground(tree.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
					tree.setHeaderForeground(tree.getDisplay().getSystemColor(SWT.COLOR_GRAY));
					tree.setBackground(tree.getDisplay().getSystemColor(SWT.COLOR_DARK_GRAY));
					tree.setForeground(tree.getDisplay().getSystemColor(SWT.COLOR_GRAY));
					System.out.println(tree.getBackground().getRGB()+ "After : tree.getBackground().getRGB()");
				}
			}
		});

		final Shell shell = new Shell(display);
		shell.setLayout(new GridLayout(2, true));

		final Control table = createTable(shell);
		final Control tree = createTree(shell);
		System.out.println(table.getBackground().getRGB() + "Just Created : table.getBackground().getRGB()");
		System.out.println(tree.getBackground().getRGB()+ "Just Created : tree.getBackground().getRGB()");

		final Button checkbox = new Button(shell, SWT.CHECK);
		checkbox.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING, false, false));
		checkbox.setText("enabled");
		checkbox.setSelection(true);
		checkbox.addListener(SWT.Selection, event -> {
			table.setEnabled(checkbox.getSelection());
			tree.setEnabled(checkbox.getSelection());
		});

		shell.setSize(400, 300);
		shell.open();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

		display.dispose();
	}

	private static Table createTable(Composite parent) {
		final Table table = new Table(parent, SWT.BORDER);
		table.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		table.setHeaderVisible(true);

		table.addListener(SWT.EraseItem, event -> {
			final Rectangle clientArea = table.getClientArea();
			event.gc.fillRectangle(clientArea.x, event.y, clientArea.width, event.height);

			event.detail &= ~(SWT.FOREGROUND | SWT.BACKGROUND | SWT.HOT | SWT.SELECTED);
		});
		table.addListener(SWT.PaintItem, event -> {
			event.gc.drawText(((Item)event.item).getText(), event.x, event.y);
		});

		final TableColumn column = new TableColumn(table, SWT.LEFT);
		column.setText("Column");
		column.setWidth(150);

		new TableItem(table, SWT.LEFT).setText("Item 1");
		new TableItem(table, SWT.LEFT).setText("Item 2");
		return table;
	}

	private static Tree createTree(Composite parent) {
		final Tree tree = new Tree(parent, SWT.BORDER);
		tree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
		tree.setHeaderVisible(true);

		tree.addListener(SWT.EraseItem, event -> {
			event.gc.setClipping((Rectangle)null);
			final Rectangle clientArea = tree.getClientArea();
			event.gc.fillRectangle(clientArea.x, event.y, clientArea.width, event.height);

			event.detail &= ~(SWT.FOREGROUND | SWT.BACKGROUND | SWT.HOT | SWT.SELECTED);
		});
		tree.addListener(SWT.PaintItem, event -> {
			event.gc.drawText(((Item)event.item).getText(), event.x, event.y);
		});

		new TreeItem(tree, SWT.LEFT).setText("Item 1");
		new TreeItem(tree, SWT.LEFT).setText("Item 2");
		return tree;
	}
}

Slight modifications done in display.addListener(), not much. My observation here is as below corresponds to RGB {255, 255, 255}Just Created : table.getBackground().getRGB() - white corresponds to RGB {128, 128, 128}After : table.getBackground().getRGB() - light gray corresponds to RGB {32, 32, 32}Before : table.getBackground().getRGB() - dark gray corresponds to RGB {0, 0, 0}Before : table.getBackground().getRGB() - black

So from this atleast i feel when first created all the widgets get background(white) then when skin is applied respective theme gets applied. On top of it as you set with setBackground gets applied.

Can you try this and see what you want can be achieved or not?

fyi : I tried to map colors from ControlExample -> Tree/Table -> change background "change" custom color palatte.

Image

deepika-u avatar Feb 24 '25 15:02 deepika-u

Sorry, I don't understand what you suggest. Your change only sets different gray colors, the problem remains.

tmssngr avatar Feb 25 '25 12:02 tmssngr