diff options
author | Eric Williams | 2018-06-20 13:58:02 +0000 |
---|---|---|
committer | Eric Williams | 2018-07-03 15:29:35 +0000 |
commit | 089e20dd5dd1cda17e7f3cad6f6838423b58074f (patch) | |
tree | f680efaebe44d6bbdeeec451af2fbb815445c1a1 /tests | |
parent | 5b059c753c4145ff08c434a27ea7776a245547bc (diff) | |
download | eclipse.platform.swt-089e20dd5dd1cda17e7f3cad6f6838423b58074f.tar.gz eclipse.platform.swt-089e20dd5dd1cda17e7f3cad6f6838423b58074f.tar.xz eclipse.platform.swt-089e20dd5dd1cda17e7f3cad6f6838423b58074f.zip |
Bug 475784: half transparent composite as overlay composite not work
with gtk3
ATTEMPT #2: fix regression from original patch. Instead of keeping the
NO_BACKGROUND flag, cache it in Control and remove it as intended in
Composite.checkStyle().
Original commit message:
We have to handle some corner case drawing situations, since
Control.setRegion() now uses Cairo entirely. In particular, we need to
handle the case where a user is using an SWT.NO_BACKGROUND Composite as
an overlay. This means the Composite has a region set, and a
paintListener attached to perform custom drawing.
Previously, Control.setRegion() "physically" manipulate the Composite's
GdkWindow to prevent any drawing outside the given region. Since Cairo
is now responsible for drawing the set region we have to handle this
geometry ourselves.
This patch fixes numerous issues all rolled into one. First, it adds a
field in GCData which corresponds to the Cairo region. This is set in
gtk_draw() so that GC.fill* methods will clip themselves accordingly and
not fill where they aren't supposed to.
Second, it checks for a PaintListener, NO_BACKGROUND, and a region being
set. If these conditions are met, we draw a transparent background in
Control.drawBackground() to ensure the region and custom drawing
succeeds.
Last, we copy the region at the Cairo level to ensure there are no
crashes when calling setRegion(region) followed by region.dispose().
Tested on GTK3.22 using the snippet attached and a child Eclipse. No
AllNonBrowser JUnit tests fail.
Change-Id: I6a6245052e9756d6c9bdd0e46ef20a74413acc6b
Signed-off-by: Eric Williams <ericwill@redhat.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug475784_TransparentComposite.java | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug475784_TransparentComposite.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug475784_TransparentComposite.java new file mode 100644 index 0000000000..800ad78429 --- /dev/null +++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug475784_TransparentComposite.java @@ -0,0 +1,248 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat - initial API and implementation + *******************************************************************************/ +package org.eclipse.swt.tests.gtk.snippets; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Path; +import org.eclipse.swt.graphics.PathData; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.graphics.Region; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; + +public class Bug475784_TransparentComposite extends Shell +{ + public static int RADIUS_OF_ROUND_EDGES = 30; + + /** + * Launch the application. + * @param args + */ + public static void main(String args[]) + { + try + { + Display display = Display.getDefault(); + Bug475784_TransparentComposite shell = new Bug475784_TransparentComposite(display); + shell.open(); + shell.layout(); + while (!shell.isDisposed()) + { + if (!display.readAndDispatch()) + { + display.sleep(); + } + } + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + /** + * Create the shell. + * @param display + */ + public Bug475784_TransparentComposite(final Display display) + { + super(display, SWT.SHELL_TRIM); + setLayout(new GridLayout(1, false)); + final Composite composite = new Composite(this, SWT.NONE); + composite.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); + composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1)); + composite.setLayout(new GridLayout(1, false)); + //overlay composite + final Composite overlay = new Composite(composite, SWT.NO_BACKGROUND | SWT.NO_FOCUS); + overlay.setLayout(new FillLayout()); + overlay.setVisible(false); + //label + Label textLabel = new Label(composite, SWT.NONE); + textLabel.setText("Hello World!\nHello World!"); + Button btnCheckButton = new Button(composite, SWT.CHECK); + btnCheckButton.setText("Check Button"); + Button btnRadioButton = new Button(composite, SWT.RADIO); + btnRadioButton.setText("Radio Button"); + //Composite for drawings + Composite compDraws = new Composite(composite, SWT.NONE); + compDraws.addPaintListener(e -> { + e.gc.setBackground(display.getSystemColor(SWT.COLOR_RED)); + e.gc.fillArc(0, 0, 50, 50, 0, 360); + }); + //exclude overlay composite + GridData gData = new GridData(); + gData.exclude = true; + overlay.setLayoutData(gData); + //set region + Region reg = new Region(); + getRegionForRoundRectangle(reg, 0, 0, 200, 200, RADIUS_OF_ROUND_EDGES); + overlay.setRegion(reg); + reg.dispose(); + //toggle overlay button + final Button btnNewButton = new Button(composite, SWT.NONE); + btnNewButton.setLayoutData(new GridData(SWT.LEFT, SWT.BOTTOM, false, true, 1, 1)); + btnNewButton.setText("Toggle overlay"); + GridData gdDataButton = new GridData(GridData.VERTICAL_ALIGN_END); + gdDataButton.horizontalAlignment = SWT.LEFT; + gdDataButton.verticalAlignment = SWT.BOTTOM; + gdDataButton.grabExcessVerticalSpace = true; + btnNewButton.setLayoutData(gdDataButton); + btnNewButton.addSelectionListener(new SelectionAdapter() + { + @Override + public void widgetSelected(SelectionEvent e) + { + int width = composite.getSize().x; + int height = composite.getSize().y - btnNewButton.getSize().y - 10; + overlay.setSize(width, height); + overlay.setVisible(!overlay.isVisible()); + } + }); + overlay.moveAbove(null); + overlay.addPaintListener(e -> { + e.gc.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_YELLOW)); + e.gc.setAlpha(150); + e.gc.fillRectangle(new Rectangle(0, 0, overlay.getSize().x, overlay.getSize().y)); + }); + createContents(); + } + + /** + * Create contents of the shell. + */ + protected void createContents() + { + setText("SWT Application"); + setSize(450, 300); + } + + @Override + protected void checkSubclass() + { + // Disable the check that prevents subclassing of SWT components + } + + public static void getCircleRegion(Region region, int r, int offsetX, int offsetY) + { + int[] polygon = new int[8 * r + 4]; + // x^2 + y^2 = r^2 + for (int i = 0; i < 2 * r + 1; i++) + { + int x = i - r; + int y = (int) Math.sqrt(r * r - x * x); + polygon[2 * i] = offsetX + x; + polygon[2 * i + 1] = offsetY + y; + polygon[8 * r - 2 * i - 2] = offsetX + x; + polygon[8 * r - 2 * i - 1] = offsetY - y; + } + region.add(polygon); + } + + public static void drawRoundFrame(GC gc, int width, int height) + { + Rectangle tmpClippingRect = gc.getClipping(); + Region reg = new Region(); + gc.getClipping(reg); + Region roundReg = new Region(); + getRegionForRoundRectangle(roundReg, 1, 1, width, height, RADIUS_OF_ROUND_EDGES - 1); + reg.subtract(roundReg); + gc.setClipping(reg); + gc.fillRectangle(0, 0, width + 1, height + 1); + reg.dispose(); + roundReg.dispose(); + gc.setClipping(tmpClippingRect); + } + + public static void loadPath(Region region, float[] points, byte[] types) + { + int start = 0, end = 0; + for (int i = 0; i < types.length; i++) + { + switch (types[i]) + { + case SWT.PATH_MOVE_TO: + { + if (start != end) + { + int n = 0; + int[] temp = new int[end - start]; + for (int k = start; k < end; k++) + { + temp[n++] = Math.round(points[k]); + } + region.add(temp); + } + start = end; + end += 2; + break; + } + case SWT.PATH_LINE_TO: + { + end += 2; + break; + } + case SWT.PATH_CLOSE: + { + if (start != end) + { + int n = 0; + int[] temp = new int[end - start]; + for (int k = start; k < end; k++) + { + temp[n++] = Math.round(points[k]); + } + region.add(temp); + } + start = end; + break; + } + } + } + } + + public static Path getPathForRoundRectangle(int x, int y, int width, int height, int r) + { + Path path = new Path(Display.getDefault()); + path.addArc(x, y, 2 * r, 2 * r, 0, 360); + path.addArc(width - 2 * r, y, 2 * r, 2 * r, 0, 360); + path.addArc(x, height - 2 * r, 2 * r, 2 * r, 0, 360); + path.addArc(width - 2 * r, height - 2 * r, 2 * r, 2 * r, 0, 360); + path.addRectangle(x, r - y, width - x, height - 2 * r); + path.addRectangle(r - x, y, width - 2 * r, height - y); + Path path2 = new Path(Display.getDefault(), path, 0.0001f); + path.dispose(); + return path2; + } + + public static void drawRoundRectangleByPath(GC gc, int x, int y, int width, int height) + { + Path path = getPathForRoundRectangle(x, y, width, height, RADIUS_OF_ROUND_EDGES - 1); + gc.drawPath(path); + path.dispose(); + } + + public static void getRegionForRoundRectangle(Region reg, int x, int y, int width, int height, int r) + { + Path tmpPath = getPathForRoundRectangle(x, y, width, height, r); + PathData data = tmpPath.getPathData(); + tmpPath.dispose(); + loadPath(reg, data.points, data.types); + } +}
\ No newline at end of file |