blob: 9d1305e1eab22c8d0ba477cbb95c882ae3a816ca [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2013, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ecommons.ui.dialogs;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.Geometry;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Monitor;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.statet.ecommons.ui.SharedUIResources;
import org.eclipse.statet.ecommons.ui.util.LayoutUtils;
import org.eclipse.statet.ecommons.ui.util.UIAccess;
public class ToolPopup {
private static final Color G_BACKGROUND = SharedUIResources.getColors().getColor(SharedUIResources.GRAPHICS_BACKGROUND_COLOR_ID);
private class SWTListener implements Listener {
@Override
public void handleEvent(final Event event) {
switch (event.type) {
case SWT.Deactivate:
if (fIgnoreActivation == 0) {
close();
}
return;
case SWT.Dispose:
dispose();
return;
case SWT.Selection:
if (event.widget == fOKButton) {
onOK();
close();
return;
}
if (event.widget == fCancelButton) {
close();
return;
}
if (event.widget == fTabFolder) {
tabSelected(getTab(fTabFolder.getSelection()));
return;
}
}
}
}
public static class ToolTab {
private final String fKey;
private final ToolPopup fParent;
private final CTabItem fTabItem;
private Composite fComposite;
public ToolTab(final String key, final ToolPopup parent,
final String name, final String tooltip) {
fKey = key;
fParent = parent;
fTabItem = new CTabItem(parent.fTabFolder, SWT.NONE);
fTabItem.setText(name);
fTabItem.setToolTipText(tooltip);
parent.fToolTabs.add(this);
}
public ToolPopup getParent() {
return fParent;
}
public CTabItem getTabItem() {
return fTabItem;
}
protected Composite create() {
final Composite composite = new Composite(fParent.getTabFolder(), SWT.NONE);
fTabItem.setControl(composite);
composite.setBackground(G_BACKGROUND);
return composite;
}
protected void activated() {
}
protected void performOK() {
fParent.onOK();
fParent.close();
}
}
protected static abstract class PreviewCanvas extends Canvas implements PaintListener {
private static final int DEFAULT_WIDTH = 50;
public PreviewCanvas(final Composite parent) {
super(parent, SWT.NONE);
addPaintListener(this);
setLayoutData(createGD());
}
@Override
public void paintControl(final PaintEvent e) {
final GC gc = e.gc;
gc.setForeground(e.display.getSystemColor(SWT.COLOR_DARK_GRAY));
final Rectangle size = getClientArea();
final int width = Math.min(DEFAULT_WIDTH, size.width / 2);
final int height = size.height - 7;
final int x0 = size.x;
final int y0 = size.y + (size.height - height) / 2;
gc.drawRectangle(x0, y0, width, height);
gc.drawRectangle(x0 + width, y0, width, height);
drawPreview(gc, 0, x0 + 1, y0 + 1, width - 2, height - 2);
drawPreview(gc, 1, x0 + width + 1, y0 + 1, width - 2, height - 2);
}
public GridData createGD() {
return new GridData(SWT.FILL, SWT.FILL, true, false);
}
@Override
public Point computeSize(final int wHint, final int hHint, final boolean changed) {
int width = 1 + DEFAULT_WIDTH * 2;
if (wHint != -1 && wHint < width) {
width = Math.max(width / 2, wHint);
}
final int height = (hHint != -1) ? hHint : (4 + LayoutUtils.defaultHSpacing());
return new Point(width, height);
}
protected abstract void drawPreview(GC gc, int idx, int x, int y, int width, int height);
}
private Shell fShell;
private CTabFolder fTabFolder;
private Button fOKButton;
private Button fCancelButton;
private final List<ToolTab> fToolTabs= new ArrayList<>();
private int fIgnoreActivation;
public ToolPopup() {
}
protected void open(final Shell parent, final Rectangle position) {
create(parent);
final Point size = fShell.getSize();
final Display display = fShell.getDisplay();
final Monitor monitor = DialogUtils.getClosestMonitor(display, position);
final Rectangle clientArea = monitor.getClientArea();
final Rectangle bounds = new Rectangle(position.x , position.y - size.y, size.x, size.y);
if (bounds.y < 0) {
bounds.y = position.y + position.height;
}
Geometry.moveInside(bounds, clientArea);
fShell.setBounds(bounds);
selectTab(getBestTab());
fShell.open();
}
public boolean isActive() {
return (UIAccess.isOkToUse(fShell) && fShell.isVisible());
}
public void close() {
if (UIAccess.isOkToUse(fShell)) {
fShell.close();
}
dispose();
}
public void dispose() {
if (fShell != null) {
if (!fShell.isDisposed()) {
fShell.dispose();
}
onDispose();
fShell = null;
}
}
private void create(final Shell parent) {
if (UIAccess.isOkToUse(fShell)) {
if (fShell.getParent() == parent) {
return;
}
dispose();
}
fToolTabs.clear();
fShell = new Shell(parent, SWT.ON_TOP | SWT.TOOL); // SWT.RESIZE
fShell.setText("Color");
fShell.setFont(JFaceResources.getDialogFont());
fShell.setSize(320, 300);
{ final GridLayout gl = new GridLayout();
gl.marginHeight = 0;
gl.marginWidth = 0;
gl.horizontalSpacing = 0;
gl.verticalSpacing = 0;
fShell.setLayout(gl);
}
final SWTListener listener = new SWTListener();
parent.addListener(SWT.Dispose, listener);
fShell.addListener(SWT.Deactivate, listener);
fShell.setBackground(fShell.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
fShell.setBackgroundMode(SWT.INHERIT_FORCE);
fTabFolder = new CTabFolder(fShell, SWT.BOTTOM | SWT.FLAT);
fTabFolder.setSimple(true);
fTabFolder.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fTabFolder.setSelectionBackground(G_BACKGROUND);
addTabs(fTabFolder);
final Composite commonBar = new Composite(fShell, SWT.NONE);
commonBar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
commonBar.setLayout(LayoutUtils.newContentGrid(3));
// final Composite status = new Composite(commonBar, SWT.NONE);
// status.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
addStatusControls(commonBar);
fOKButton = new Button(commonBar, SWT.PUSH | SWT.FLAT);
fOKButton.setText(IDialogConstants.OK_LABEL);
fOKButton.setFont(fShell.getFont());
fOKButton.addListener(SWT.Selection, listener);
fCancelButton = new Button(commonBar, SWT.PUSH | SWT.FLAT);
fCancelButton.setText(IDialogConstants.CANCEL_LABEL);
fCancelButton.setFont(fShell.getFont());
fCancelButton.addListener(SWT.Selection, listener);
{ final Point size = fOKButton.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
size.x = Math.max(size.x, fCancelButton.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
{ final GridData gd = new GridData(SWT.FILL, SWT.FILL);
gd.widthHint = size.x;
gd.heightHint = size.y - 2;
fOKButton.setLayoutData(gd);
}
{ final GridData gd = new GridData(SWT.FILL, SWT.FILL);
gd.widthHint = size.x;
gd.heightHint = size.y - 2;
fCancelButton.setLayoutData(gd);
}
}
fTabFolder.addListener(SWT.Selection, listener);
fShell.setDefaultButton(fOKButton);
fShell.pack();
}
public Shell getShell() {
return fShell;
}
protected CTabFolder getTabFolder() {
return fTabFolder;
}
protected ToolTab getTab(final String key) {
for (final ToolTab tab : fToolTabs) {
if (tab.fKey == key) {
return tab;
}
}
return null;
}
protected ToolTab getTab(final CTabItem item) {
for (final ToolTab tab : fToolTabs) {
if (tab.fTabItem == item) {
return tab;
}
}
return null;
}
protected void addStatusControls(final Composite composite) {
}
protected void addTabs(final CTabFolder tabFolder) {
}
protected ToolTab getBestTab() {
return null;
}
protected void selectTab(final ToolTab tab) {
if (tab != null) {
final CTabItem tabItem = tab.getTabItem();
fTabFolder.setSelection(tabItem);
tabSelected(tab);
final Display display = fShell.getDisplay();
final Control focusControl = display.getFocusControl();
display.asyncExec(new Runnable() {
@Override
public void run() {
if (UIAccess.isOkToUse(fTabFolder)
&& fTabFolder.getSelection() == tabItem
&& display.getFocusControl() == focusControl) {
tabItem.getControl().setFocus();
}
}
});
}
}
protected void tabSelected(final ToolTab tab) {
if (tab != null) {
tab.activated();
tab.getTabItem().getControl().setFocus();
}
}
public void beginIgnoreActivation() {
fIgnoreActivation++;
}
public void endIgnoreActivation() {
fIgnoreActivation--;
}
protected void onDispose() {
fTabFolder = null;
fToolTabs.clear();
}
protected void onOK() {
}
}