Fixes launchbar icons looking blurry on hidpi screens
The launchbar way of compositing images for the buttons was preventing the use of higher quality icons on hidpi dislays, making the launchbar buttons look blurry or pixelated compared to other toolbar buttons. Instead we can get a nicer result with a custom widget on which we can directly draw a button border plus the hidpi version of the icon. Also included is an attempt at a 2x hammer build button icon, which should look a bit nicer on hidpi screens.
BIN
core/org.eclipse.cdt.ui/icons/dlcl16/build_exec@2x.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
core/org.eclipse.cdt.ui/icons/elcl16/build_exec@2x.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 620 B |
Before Width: | Height: | Size: 330 B |
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 QNX Software Systems and others.
|
||||
* Copyright (c) 2016, 2022 QNX Software Systems and others.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
|
@ -13,6 +13,7 @@ package org.eclipse.launchbar.ui.controls.internal;
|
|||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.jface.resource.ImageRegistry;
|
||||
import org.eclipse.ui.plugin.AbstractUIPlugin;
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
@ -27,10 +28,7 @@ public class Activator extends AbstractUIPlugin {
|
|||
public static final String PLUGIN_ID = "org.eclipse.launchbar.ui.controls"; //$NON-NLS-1$
|
||||
|
||||
// images
|
||||
public static final String IMG_BUTTON_BACKGROUND = "bgButton"; //$NON-NLS-1$
|
||||
public static final String IMG_BUTTON_BUILD = "build"; //$NON-NLS-1$
|
||||
public static final String IMG_BUTTON_LAUNCH = "launch"; //$NON-NLS-1$
|
||||
public static final String IMG_BUTTON_STOP = "stop"; //$NON-NLS-1$
|
||||
public static final String IMG_CONFIG_CONFIG = "config_config"; //$NON-NLS-1$
|
||||
public static final String IMG_EDIT_COLD = "edit_cold"; //$NON-NLS-1$
|
||||
|
||||
|
@ -47,14 +45,14 @@ public class Activator extends AbstractUIPlugin {
|
|||
public void start(BundleContext context) throws Exception {
|
||||
super.start(context);
|
||||
plugin = this;
|
||||
}
|
||||
|
||||
ImageRegistry imageRegistry = getImageRegistry();
|
||||
imageRegistry.put(IMG_BUTTON_BACKGROUND, imageDescriptorFromPlugin(PLUGIN_ID, "icons/bgButton.png")); //$NON-NLS-1$
|
||||
imageRegistry.put(IMG_BUTTON_BUILD, imageDescriptorFromPlugin(PLUGIN_ID, "icons/build_16.png")); //$NON-NLS-1$
|
||||
imageRegistry.put(IMG_BUTTON_LAUNCH, imageDescriptorFromPlugin(PLUGIN_ID, "icons/launch_16.png")); //$NON-NLS-1$
|
||||
imageRegistry.put(IMG_BUTTON_STOP, imageDescriptorFromPlugin(PLUGIN_ID, "icons/stop_16.png")); //$NON-NLS-1$
|
||||
imageRegistry.put(IMG_CONFIG_CONFIG, imageDescriptorFromPlugin(PLUGIN_ID, "icons/config_config.png")); //$NON-NLS-1$
|
||||
imageRegistry.put(IMG_EDIT_COLD, imageDescriptorFromPlugin(PLUGIN_ID, "icons/edit_cold.png")); //$NON-NLS-1$
|
||||
@Override
|
||||
protected void initializeImageRegistry(ImageRegistry reg) {
|
||||
reg.put(IMG_BUTTON_BUILD, ImageDescriptor.createFromURL(plugin.getBundle().getEntry("/icons/build_exec.png"))); //$NON-NLS-1$
|
||||
reg.put(IMG_CONFIG_CONFIG,
|
||||
ImageDescriptor.createFromURL(plugin.getBundle().getEntry("/icons/config_config.png"))); //$NON-NLS-1$
|
||||
reg.put(IMG_EDIT_COLD, ImageDescriptor.createFromURL(plugin.getBundle().getEntry("/icons/edit_cold.png"))); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2022 Mat Booth and others.
|
||||
*
|
||||
* 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.launchbar.ui.controls.internal;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.MouseListener;
|
||||
import org.eclipse.swt.events.MouseTrackListener;
|
||||
import org.eclipse.swt.events.SelectionListener;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Canvas;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.TypedListener;
|
||||
|
||||
/**
|
||||
* Customised toolbar item button for the build/launch/stop launch bar buttons.
|
||||
*/
|
||||
public class CLaunchButton extends Canvas {
|
||||
|
||||
private Image image;
|
||||
|
||||
// Mouse states
|
||||
private boolean hover;
|
||||
private boolean pressed;
|
||||
|
||||
public CLaunchButton(Composite parent, int style) {
|
||||
super(parent, style);
|
||||
|
||||
addPaintListener(e -> {
|
||||
if (pressed && hover) {
|
||||
e.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
|
||||
} else if (hover) {
|
||||
e.gc.setBackground(getDisplay().getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW));
|
||||
} else {
|
||||
e.gc.setBackground(getBackground());
|
||||
}
|
||||
int arc = 3;
|
||||
Point size = getSize();
|
||||
e.gc.fillRoundRectangle(0, 0, size.x - 1, size.y - 1, arc, arc);
|
||||
if (image != null) {
|
||||
e.gc.drawImage(image, 10, 5);
|
||||
}
|
||||
e.gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW));
|
||||
e.gc.drawRoundRectangle(0, 0, size.x - 1, size.y - 1, arc, arc);
|
||||
});
|
||||
|
||||
addMouseMoveListener(e -> {
|
||||
// We don't get enter and exit events whilst a mouse button is down i.e., during click-drag,
|
||||
// so we also need to track the hover state here because during a click-drag we still get
|
||||
// move events even when the pointer is not over the control
|
||||
if (e.getSource() instanceof Control button) {
|
||||
Point size = button.getSize();
|
||||
if (e.x >= 0 && e.x < size.x && e.y >= 0 && e.y < size.y) {
|
||||
hover = true;
|
||||
} else {
|
||||
hover = false;
|
||||
}
|
||||
redraw();
|
||||
}
|
||||
});
|
||||
addMouseTrackListener(MouseTrackListener.mouseEnterAdapter(e -> {
|
||||
hover = true;
|
||||
redraw();
|
||||
}));
|
||||
addMouseTrackListener(MouseTrackListener.mouseExitAdapter(e -> {
|
||||
hover = false;
|
||||
redraw();
|
||||
}));
|
||||
addMouseListener(MouseListener.mouseDownAdapter(e -> {
|
||||
pressed = true;
|
||||
redraw();
|
||||
}));
|
||||
addMouseListener(MouseListener.mouseUpAdapter(e -> {
|
||||
if (pressed && hover) {
|
||||
notifyListeners(SWT.Selection, null);
|
||||
}
|
||||
pressed = false;
|
||||
redraw();
|
||||
}));
|
||||
}
|
||||
|
||||
public void addSelectionListener(SelectionListener listener) {
|
||||
checkWidget();
|
||||
if (listener == null) {
|
||||
SWT.error(SWT.ERROR_NULL_ARGUMENT);
|
||||
}
|
||||
TypedListener typedListener = new TypedListener(listener);
|
||||
addListener(SWT.Selection, typedListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point computeSize(int wHint, int hHint, boolean changed) {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
if (image != null) {
|
||||
Rectangle bounds = image.getBounds();
|
||||
width = bounds.width + 20;
|
||||
height = bounds.height + 10;
|
||||
}
|
||||
return new Point(width, height);
|
||||
}
|
||||
|
||||
public void setImage(Image image) {
|
||||
this.image = image;
|
||||
redraw();
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 QNX Software Systems and others.
|
||||
*
|
||||
* 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:
|
||||
* Doug Schaefer - initial API and implementation
|
||||
* Elena Laskavaia - moved to a separate class
|
||||
*******************************************************************************/
|
||||
package org.eclipse.launchbar.ui.controls.internal;
|
||||
|
||||
import org.eclipse.jface.resource.CompositeImageDescriptor;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
|
||||
/**
|
||||
* This class will take two images and create descriptor that will overlay them, mainImage will be centered
|
||||
*/
|
||||
public class LaunchBarButtonImageDescriptor extends CompositeImageDescriptor {
|
||||
private Image bgImage;
|
||||
private Image mainImage;
|
||||
|
||||
/**
|
||||
* @param mainImage - main image, will be centered
|
||||
* @param bgImage - background image
|
||||
*/
|
||||
public LaunchBarButtonImageDescriptor(Image mainImage, Image bgImage) {
|
||||
super();
|
||||
this.bgImage = bgImage;
|
||||
this.mainImage = mainImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Point getSize() {
|
||||
Rectangle bounds = bgImage.getBounds();
|
||||
return new Point(bounds.width - bounds.y, bounds.height - bounds.x);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void drawCompositeImage(int width, int height) {
|
||||
drawImage(bgImage.getImageData(), 0, 0);
|
||||
Rectangle bgBounds = bgImage.getBounds();
|
||||
Rectangle modeBounds = mainImage.getBounds();
|
||||
int x = ((bgBounds.width - bgBounds.x) - (modeBounds.width - modeBounds.x)) / 2;
|
||||
int y = ((bgBounds.height - bgBounds.y) - (modeBounds.height - modeBounds.y)) / 2;
|
||||
drawImage(mainImage.getImageData(), x, y);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2018 QNX Software Systems and others.
|
||||
* Copyright (c) 2014, 2022 QNX Software Systems and others.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
|
@ -23,8 +23,9 @@ import org.eclipse.core.commands.ExecutionEvent;
|
|||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.OperationCanceledException;
|
||||
import org.eclipse.debug.core.ILaunchMode;
|
||||
import org.eclipse.debug.ui.DebugUITools;
|
||||
import org.eclipse.debug.ui.IDebugUIConstants;
|
||||
import org.eclipse.jface.preference.IPreferenceStore;
|
||||
import org.eclipse.jface.resource.ImageDescriptor;
|
||||
import org.eclipse.launchbar.core.ILaunchBarListener;
|
||||
import org.eclipse.launchbar.core.ILaunchBarManager;
|
||||
import org.eclipse.launchbar.core.ILaunchDescriptor;
|
||||
|
@ -33,13 +34,12 @@ import org.eclipse.launchbar.ui.ILaunchBarUIConstants;
|
|||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.SelectionAdapter;
|
||||
import org.eclipse.swt.graphics.Image;
|
||||
import org.eclipse.swt.layout.FillLayout;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.ToolBar;
|
||||
import org.eclipse.swt.widgets.ToolItem;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.commands.ICommandService;
|
||||
import org.eclipse.ui.handlers.IHandlerService;
|
||||
|
@ -71,18 +71,22 @@ public class LaunchBarControl implements ILaunchBarListener {
|
|||
container.setLayout(layout);
|
||||
container.addDisposeListener(e -> LaunchBarControl.this.dispose());
|
||||
|
||||
ToolBar toolBar = new ToolBar(container, SWT.FLAT);
|
||||
Composite buttons = new Composite(container, SWT.NONE);
|
||||
FillLayout fillLayout = new FillLayout();
|
||||
fillLayout.spacing = 5;
|
||||
buttons.setLayout(fillLayout);
|
||||
|
||||
IPreferenceStore store = Activator.getDefault().getPreferenceStore();
|
||||
boolean buildEnabled = store.getBoolean(Activator.PREF_ENABLE_BUILDBUTTON);
|
||||
if (buildEnabled) {
|
||||
createButton(toolBar, Activator.IMG_BUTTON_BUILD, Messages.LaunchBarControl_Build,
|
||||
ILaunchBarUIConstants.CMD_BUILD);
|
||||
Image imageBuild = Activator.getDefault().getImageRegistry().get(Activator.IMG_BUTTON_BUILD);
|
||||
createButton(buttons, imageBuild, Messages.LaunchBarControl_Build, ILaunchBarUIConstants.CMD_BUILD);
|
||||
}
|
||||
|
||||
createButton(toolBar, Activator.IMG_BUTTON_LAUNCH, Messages.LaunchBarControl_Launch,
|
||||
ILaunchBarUIConstants.CMD_LAUNCH);
|
||||
createButton(toolBar, Activator.IMG_BUTTON_STOP, Messages.LaunchBarControl_Stop,
|
||||
ILaunchBarUIConstants.CMD_STOP);
|
||||
Image imageLaunch = DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_LAUNCH_RUN);
|
||||
createButton(buttons, imageLaunch, Messages.LaunchBarControl_Launch, ILaunchBarUIConstants.CMD_LAUNCH);
|
||||
Image imageStop = DebugUITools.getImage(IDebugUIConstants.IMG_OBJS_LAUNCH_RUN_TERMINATED);
|
||||
createButton(buttons, imageStop, Messages.LaunchBarControl_Stop, ILaunchBarUIConstants.CMD_STOP);
|
||||
|
||||
modeSelector = new ModeSelector(container, SWT.NONE);
|
||||
modeSelector.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
|
||||
|
@ -139,14 +143,9 @@ public class LaunchBarControl implements ILaunchBarListener {
|
|||
manager.removeListener(this);
|
||||
}
|
||||
|
||||
private ToolItem createButton(Composite parent, String imageName, String toolTipText, final String commandId) {
|
||||
ToolItem button = new ToolItem((ToolBar) parent, SWT.FLAT);
|
||||
private CLaunchButton createButton(Composite parent, Image image, String toolTipText, final String commandId) {
|
||||
CLaunchButton button = new CLaunchButton(parent, SWT.NONE);
|
||||
|
||||
Image bgImage = Activator.getDefault().getImageRegistry().get(Activator.IMG_BUTTON_BACKGROUND);
|
||||
Image fgImage = Activator.getDefault().getImageRegistry().get(imageName);
|
||||
|
||||
ImageDescriptor imageDesc = new LaunchBarButtonImageDescriptor(fgImage, bgImage);
|
||||
Image image = imageDesc.createImage();
|
||||
button.setImage(image);
|
||||
button.setToolTipText(toolTipText);
|
||||
button.setData("command", commandId); //$NON-NLS-1$
|
||||
|
@ -167,7 +166,6 @@ public class LaunchBarControl implements ILaunchBarListener {
|
|||
}
|
||||
}
|
||||
});
|
||||
button.addDisposeListener(e -> image.dispose());
|
||||
return button;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2014, 2018 QNX Software Systems and others.
|
||||
* Copyright (c) 2014, 2022 QNX Software Systems and others.
|
||||
*
|
||||
* This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License 2.0
|
||||
|
@ -34,13 +34,10 @@ import org.eclipse.swt.graphics.Image;
|
|||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.ToolBar;
|
||||
import org.eclipse.swt.widgets.ToolItem;
|
||||
|
||||
public class ModeSelector extends CSelector {
|
||||
private static final String[] noModes = new String[] { "---" }; //$NON-NLS-1$
|
||||
private final ILaunchBarManager manager = Activator.getService(ILaunchBarManager.class);
|
||||
private Map<String, Image> modeButtonImages = new HashMap<>();
|
||||
|
||||
public ModeSelector(Composite parent, int style) {
|
||||
super(parent, style);
|
||||
|
@ -135,15 +132,6 @@ public class ModeSelector extends CSelector {
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
|
||||
for (Image image : modeButtonImages.values()) {
|
||||
image.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
protected ILaunchGroup getDefaultLaunchGroup(String mode) {
|
||||
String groupId;
|
||||
if (mode.equals(ILaunchManager.DEBUG_MODE)) {
|
||||
|
@ -196,14 +184,15 @@ public class ModeSelector extends CSelector {
|
|||
updateLaunchButton(findLaunchButton());
|
||||
}
|
||||
|
||||
private ToolItem findLaunchButton() {
|
||||
private CLaunchButton findLaunchButton() {
|
||||
String commandId = ILaunchBarUIConstants.CMD_LAUNCH;
|
||||
// Launchbar buttons are grouped in a composite that is a sibling to this
|
||||
for (Control control : getParent().getChildren()) {
|
||||
if (control instanceof ToolBar) {
|
||||
for (ToolItem toolItem : ((ToolBar) control).getItems()) {
|
||||
if (commandId.equals(toolItem.getData("command"))) { //$NON-NLS-1$
|
||||
if (control instanceof Composite comp) {
|
||||
for (Control button : comp.getChildren()) {
|
||||
if (commandId.equals(button.getData("command"))) { //$NON-NLS-1$
|
||||
// found launch button
|
||||
return toolItem;
|
||||
return (CLaunchButton) button;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,27 +201,15 @@ public class ModeSelector extends CSelector {
|
|||
return null;
|
||||
}
|
||||
|
||||
private void updateLaunchButton(ToolItem toolItem) {
|
||||
if (toolItem == null || isDisposed()) {
|
||||
private void updateLaunchButton(CLaunchButton button) {
|
||||
if (button == null || isDisposed()) {
|
||||
return;
|
||||
}
|
||||
Object selection = getSelection();
|
||||
if (selection instanceof ILaunchMode) {
|
||||
ILaunchMode mode = (ILaunchMode) selection;
|
||||
toolItem.setToolTipText(NLS.bind(Messages.ModeSelector_ToolTip, mode.getLabel()));
|
||||
ILaunchGroup group = getLaunchGroup(mode);
|
||||
// we cannot use mode id as id, since external tool group and run group have same "run" id for the mode
|
||||
// but different images
|
||||
String id = group.getIdentifier();
|
||||
Image image = modeButtonImages.get(id);
|
||||
if (image == null) {
|
||||
Image bgImage = Activator.getDefault().getImageRegistry().get(Activator.IMG_BUTTON_BACKGROUND);
|
||||
Image modeImage = getLabelProvider().getImage(mode);
|
||||
ImageDescriptor imageDesc = new LaunchBarButtonImageDescriptor(modeImage, bgImage);
|
||||
image = imageDesc.createImage();
|
||||
modeButtonImages.put(id, image);
|
||||
}
|
||||
toolItem.setImage(image);
|
||||
if (selection instanceof ILaunchMode mode) {
|
||||
button.setToolTipText(NLS.bind(Messages.ModeSelector_ToolTip, mode.getLabel()));
|
||||
Image image = getLabelProvider().getImage(mode);
|
||||
button.setImage(image);
|
||||
}
|
||||
}
|
||||
|
||||
|
|