diff --git a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF index 585219082466..74f698f50f07 100644 --- a/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.jface.text/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.jface.text -Bundle-Version: 3.30.0.qualifier +Bundle-Version: 3.30.100.qualifier Bundle-Vendor: %providerName Bundle-Localization: plugin Export-Package: diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/CompletionProposalDrawSupport.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/CompletionProposalDrawSupport.java new file mode 100644 index 000000000000..3ac82ef07dd9 --- /dev/null +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/CompletionProposalDrawSupport.java @@ -0,0 +1,85 @@ +/******************************************************************************* + * Copyright (c) 2025 SAP SE. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * SAP SE - initial API and implementation + *******************************************************************************/ +package org.eclipse.jface.internal.text; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Scrollable; +import org.eclipse.swt.widgets.Table; + +import org.eclipse.jface.viewers.ColumnViewerSelectionColorListener; + +/** + * Provides custom drawing support for completion proposals. This class ensures that completion + * proposals are always rendered with a focused appearance. + * + *
+ * This drawing behavior addresses the particular situation where the code completion is triggered + * via keyboard shortcut, leaving the editor focused. In such cases, without this custom drawing + * support, the completion proposal would appear unfocused, leading to a suboptimal coloring. + *
+ */ +public class CompletionProposalDrawSupport implements Listener { + + /** + * Delegate + */ + private final TableOwnerDrawSupport fTableOwnerDrawSupport; + + private CompletionProposalDrawSupport(Table table) { + fTableOwnerDrawSupport= new TableOwnerDrawSupport(table); + } + + public static void install(Table table) { + CompletionProposalDrawSupport listener= new CompletionProposalDrawSupport(table); + + // Since this listener delegates to TableOwnerDrawSupport right after doing + // its own stuff, we need to make sure to listen for all kind of events so + // that the delegation happens even after a No-Op. + table.addListener(SWT.Dispose, listener); + table.addListener(SWT.MeasureItem, listener); + table.addListener(SWT.EraseItem, listener); + table.addListener(SWT.PaintItem, listener); + } + + @Override + public void handleEvent(Event event) { + + if (event.widget instanceof Control && event.gc != null) { + + boolean isSelected= (event.detail & SWT.SELECTED) != 0; + + if (event.type == SWT.EraseItem && isSelected) { + + final Color backgroundColor= ColumnViewerSelectionColorListener.getSelectionBackgroundColor(event.display, isSelected); + event.gc.setBackground(backgroundColor); + + final int width= (event.widget instanceof Scrollable s) ? s.getClientArea().width : event.width; + event.gc.fillRectangle(0, event.y, width, event.height); + + // Prevent native selection drawing + event.detail&= ~SWT.SELECTED; + + } else if (event.type == SWT.PaintItem) { + final Color foregroundColor= ColumnViewerSelectionColorListener.getSelectionForegroundColor(event.display, isSelected); + event.gc.setForeground(foregroundColor); + } + } + + fTableOwnerDrawSupport.handleEvent(event); + } +} diff --git a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/TableOwnerDrawSupport.java b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/TableOwnerDrawSupport.java index 7f4e72a346df..219d080a3909 100644 --- a/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/TableOwnerDrawSupport.java +++ b/bundles/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/TableOwnerDrawSupport.java @@ -27,7 +27,9 @@ /** - * Adds owner draw support for tables. + * Adds owner draw support for tables.+ * The listener provides different colors for: + *
true if other custom listeners are present that should
+ * handle selection, false otherwise
+ */
+ private boolean hasAdditionalEraseItemListeners(Event event) {
+ if (!(event.widget instanceof Control control)) {
+ return false;
+ }
+
+ Listener[] listeners = control.getListeners(SWT.EraseItem);
+ Object ownerDrawListener = control.getData(OwnerDrawLabelProvider.OWNER_DRAW_LABEL_PROVIDER_LISTENER);
+ return Arrays.stream(listeners).dropWhile(l -> l != this) // ignore listeners before "this"
+ .dropWhile(l -> l == this) // also ignore "this"
+ .anyMatch(l -> l != ownerDrawListener);
+ }
+
+ /**
+ * Gets the foreground color for a selected cell or item in a viewer.
+ *
+ * @param device The device to get the system color from (in case there is no
+ * color set in the preferences)
+ * @param focused Whether or not the control that contains the cell or item is
+ * currently focused.
+ * @return either a color set via preferences or the default system color.
+ */
+ public static Color getSelectionForegroundColor(Device device, boolean focused) {
+ return getSelectionColor(device, focused ? COLOR_SELECTION_FG_FOCUS : COLOR_SELECTION_FG_NO_FOCUS);
+ }
+
+ /**
+ * Gets the background color for a selected cell or item in a viewer.
+ *
+ * @param device The device to get the system color from (in case there is no
+ * color set in the preferences)
+ * @param focused Whether or not the control that contains the cell or item is
+ * currently focused.
+ * @return either a color set via preferences or the default system color.
+ */
+ public static Color getSelectionBackgroundColor(Device device, boolean focused) {
+ return getSelectionColor(device, focused ? COLOR_SELECTION_BG_FOCUS : COLOR_SELECTION_BG_NO_FOCUS);
+ }
+
+ private static Color getSelectionColor(Device device, String key) {
+ ColorRegistry registry = JFaceResources.getColorRegistry();
+
+ if (!registry.hasValueFor(key)) {
+ RGB systemColor = getSystemColorForId(device, key);
+ registry.put(key, systemColor);
+ }
+
+ return registry.get(key);
+ }
+
+ public static RGB getSystemColorForId(String id) {
+ return getSystemColorForId(Display.getDefault(), id);
+ }
+
+ private static RGB getSystemColorForId(Device device, String id) {
+ return device.getSystemColor(idToDefaultSWTSystemColor(id)).getRGB();
+ }
+
+ private static int idToDefaultSWTSystemColor(String id) {
+ return switch (id) {
+ case COLOR_SELECTION_BG_FOCUS -> SWT.COLOR_TITLE_BACKGROUND;
+ case COLOR_SELECTION_FG_FOCUS -> SWT.COLOR_WHITE;
+ case COLOR_SELECTION_BG_NO_FOCUS -> SWT.COLOR_TITLE_INACTIVE_BACKGROUND;
+ case COLOR_SELECTION_FG_NO_FOCUS -> SWT.COLOR_TITLE_INACTIVE_FOREGROUND;
+ default -> SWT.COLOR_LIST_SELECTION;
+ };
+ }
+
+ @Override
+ public void handleEvent(Event event) {
+ if (event.type == SWT.EraseItem) {
+ handleEraseItem(event);
+ } else if (event.type == SWT.PaintItem) {
+ handlePaintItem(event);
+ }
+ }
+
+ private void handleEraseItem(Event event) {
+ if ((event.detail & SWT.SELECTED) == 0)
+ return;
+ if (event.widget instanceof Control c && !c.isEnabled())
+ return;
+
+ // No need to process if there are more processors (other than
+ // TableOwnerDrawSupport) after this one.
+ if (hasAdditionalEraseItemListeners(event))
+ return;
+
+ Control control = (Control) event.widget;
+ GC gc = event.gc;
+
+ Color bg = getSelectionBackgroundColor(event.display, control.isFocusControl());
+
+ gc.setBackground(bg);
+
+ int rowWidth = (event.widget instanceof Scrollable s) ? s.getClientArea().width : event.width;
+ gc.fillRectangle(0, event.y, rowWidth, event.height);
+
+ // Prevent native selection drawing
+ event.detail &= ~SWT.SELECTED;
+ }
+
+ private void handlePaintItem(Event event) {
+ // We must not rely on event.detail & SWT.SELECTED because we cleared it above.
+ // Instead compute selection state from the widget.
+ if (!(event.widget instanceof Table table))
+ return;
+ if (!(event.item instanceof TableItem item))
+ return;
+
+ boolean isSelected = table.isSelected(table.indexOf(item));
+ if (!isSelected)
+ return; // only adjust painting for selected rows, otherwise leave default owner draw
+
+ GC gc = event.gc;
+
+ // Set the foreground color for selected text/icon painting, if needed
+ Color fg = getSelectionForegroundColor(event.display, table.isFocusControl());
+ gc.setForeground(fg);
+
+ // Paint the image explicitly (like TableOwnerDrawSupport does)
+ int column = event.index;
+ Image image = item.getImage(column);
+ if (image != null) {
+ Rectangle imageBounds = item.getImageBounds(column);
+ Rectangle src = image.getBounds();
+
+ int x = imageBounds.x + Math.max(0, (imageBounds.width - src.width) / 2);
+ int y = imageBounds.y + Math.max(0, (imageBounds.height - src.height) / 2);
+
+ gc.drawImage(image, x, y);
+ }
+
+ // Text painting:
+ // If TableOwnerDrawSupport is installed, it will paint the text itself.
+ // If you find text color is wrong on selected rows, you have two choices:
+ // 1) Adjust TableOwnerDrawSupport to respect gc foreground, or
+ // 2) Paint the text yourself here (requires computing text bounds and applying
+ // styles).
+ }
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/OwnerDrawLabelProvider.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/OwnerDrawLabelProvider.java
index e240ab7393df..5a7eebbcb091 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/OwnerDrawLabelProvider.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/OwnerDrawLabelProvider.java
@@ -68,7 +68,7 @@ public void handleEvent(Event event) {
}
}
- private static final String OWNER_DRAW_LABEL_PROVIDER_LISTENER = "owner_draw_label_provider_listener"; //$NON-NLS-1$
+ static final String OWNER_DRAW_LABEL_PROVIDER_LISTENER = "owner_draw_label_provider_listener"; //$NON-NLS-1$
/**
* Set up the owner draw callbacks for the viewer.
diff --git a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StructuredViewer.java b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StructuredViewer.java
index 5b1ab4432d31..2f4774bfd3f6 100644
--- a/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StructuredViewer.java
+++ b/bundles/org.eclipse.jface/src/org/eclipse/jface/viewers/StructuredViewer.java
@@ -1210,6 +1210,7 @@ public void widgetDefaultSelected(SelectionEvent e) {
});
handler.addPostSelectionListener(widgetSelectedAdapter(this::handlePostSelect));
handler.addOpenListener(StructuredViewer.this::handleOpen);
+ ColumnViewerSelectionColorListener.install(this);
}
/**
diff --git a/bundles/org.eclipse.ui.themes/META-INF/MANIFEST.MF b/bundles/org.eclipse.ui.themes/META-INF/MANIFEST.MF
index a1a0eafd8698..f9d231a3844e 100644
--- a/bundles/org.eclipse.ui.themes/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.ui.themes/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Plugin.name
Bundle-SymbolicName: org.eclipse.ui.themes;singleton:=true
-Bundle-Version: 1.2.2900.qualifier
+Bundle-Version: 1.2.3000.qualifier
Bundle-Vendor: %Plugin.providerName
Bundle-Localization: plugin
Require-Bundle: org.eclipse.e4.ui.css.swt.theme
diff --git a/bundles/org.eclipse.ui.themes/css/dark/e4-dark_preferencestyle.css b/bundles/org.eclipse.ui.themes/css/dark/e4-dark_preferencestyle.css
index 6e74b61901a1..8267a89fd83e 100644
--- a/bundles/org.eclipse.ui.themes/css/dark/e4-dark_preferencestyle.css
+++ b/bundles/org.eclipse.ui.themes/css/dark/e4-dark_preferencestyle.css
@@ -76,4 +76,6 @@ IEclipsePreferences#org-eclipse-ui-workbench:org-eclipse-ui-themes { /* pseudo a
'org.eclipse.ui.editors.rangeIndicatorColor=27,118,153'
'org.eclipse.jface.REVISION_NEWEST_COLOR=75,44,3'
'org.eclipse.jface.REVISION_OLDEST_COLOR=154,113,61'
+ 'org.eclipse.jface.SELECTION_FOREGROUND_NO_FOCUS=240,240,240'
+ 'org.eclipse.jface.SELECTION_BACKGROUND_NO_FOCUS=95,95,95'
}
diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/themes/ColumnViewerSelectionColorFactory.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/themes/ColumnViewerSelectionColorFactory.java
new file mode 100644
index 000000000000..f987cf7eafab
--- /dev/null
+++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/themes/ColumnViewerSelectionColorFactory.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2024 SAP SE.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * SAP SE - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ui.internal.themes;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExecutableExtension;
+import org.eclipse.jface.viewers.ColumnViewerSelectionColorListener;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.ui.themes.IColorFactory;
+
+/**
+ * Color factory for viewer selection colors that adapts to the OS/desktop
+ * theme. Provides default colors based on system colors for focused and
+ * unfocused selections.
+ * + * The default colors are based on system title bar colors which automatically + * adapt to light/dark themes and high contrast modes. Themes can override these + * defaults to provide custom styling. + *
+ * + * @since 3.39 + */ +public class ColumnViewerSelectionColorFactory implements IColorFactory, IExecutableExtension { + + private String color = null; + + @Override + public RGB createColor() { + return ColumnViewerSelectionColorListener.getSystemColorForId(color); + } + + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) { + if ("colorDefinition".equals(config.getName())) { //$NON-NLS-1$ + this.color = config.getAttribute("id"); //$NON-NLS-1$ + } + } +} diff --git a/bundles/org.eclipse.ui/plugin.properties b/bundles/org.eclipse.ui/plugin.properties index 27e4672696c8..3fe7bac81114 100644 --- a/bundles/org.eclipse.ui/plugin.properties +++ b/bundles/org.eclipse.ui/plugin.properties @@ -371,6 +371,15 @@ Color.revisionNewestDesc=Background color for the newest revision shown in a tex Color.revisionOldest=Oldest revision background color Color.revisionOldestDesc=Background color for the oldest revision shown in a text editor's ruler. Together with the newest revision background color this defines a gradient used for all revision from newest to oldest. +Color.viewerSelectionBackgroundFocused=Viewer selection background (focused) +Color.viewerSelectionBackgroundFocusedDesc=Background color for selected items in viewers when the control has focus. Defaults to system highlight color. (No effect on Linux) +Color.viewerSelectionForegroundFocused=Viewer selection foreground (focused) +Color.viewerSelectionForegroundFocusedDesc=Foreground color for selected items in viewers when the control has focus. (No effect on Linux) +Color.viewerSelectionBackgroundNoFocus=Viewer selection background (no focus) +Color.viewerSelectionBackgroundNoFocusDesc=Background color for selected items in viewers when the control does not have focus. (No effect on Linux) +Color.viewerSelectionForegroundNoFocus=Viewer selection foreground (no focus) +Color.viewerSelectionForegroundNoFocusDesc=Foreground color for selected items in viewers when the control does not have focus. (No effect on Linux) + Color.showKeysForeground=Keys foreground color Color.showKeysForegroundDesc=Color for foreground of the control to visualize pressed keys Color.showKeysBackground=Keys background color diff --git a/bundles/org.eclipse.ui/plugin.xml b/bundles/org.eclipse.ui/plugin.xml index 127f5dc07ef7..6911af10c291 100644 --- a/bundles/org.eclipse.ui/plugin.xml +++ b/bundles/org.eclipse.ui/plugin.xml @@ -1741,6 +1741,56 @@ + +