eclipse-platform / eclipse.platform.swt

Eclipse SWT
https://www.eclipse.org/swt/
Eclipse Public License 2.0
112 stars 135 forks source link

Issue with background Image in mac os #494

Open AsheraCordova opened 1 year ago

AsheraCordova commented 1 year ago

Describe the bug Display of background image gets distorted in mac os.

To Reproduce

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;

public class TestBgImage {
  public static void main(String[] args) {
    final Display display = new Display();
    final Shell shell = new Shell(display, SWT.SHELL_TRIM);
    shell.setBounds(0, 0, 320, 488);
    Composite composite = new Composite(shell, SWT.H_SCROLL);
    ScrollBar horizontalBar = composite.getHorizontalBar();
    if (horizontalBar != null) {
        horizontalBar.setVisible(false);
    }
    Image image = new Image(null, "output.png");
    composite.setBackgroundImage(image);
    composite.setBounds(0, 0, 95, 26);
    shell.open();
    System.out.println(shell.getBounds());
    // Set up the event loop.
    while (!shell.isDisposed()) {
      if (!display.readAndDispatch()) {
        // If no more entries in event queue
        display.sleep();
      }
    }
    display.dispose();
  }

}

Expected behavior The background image should not get tiled

Screenshots Image being displayed: output

Mac OS Issue: mac

Windows: windows

Environment:

  1. Select the platform(s) on which the behavior is seen:

      • [] All OS
      • [ ] Windows
      • [ ] Linux
      • [x ] macOS
  2. Additional OS info (e.g. OS version, Linux Desktop, etc) MacOS Big Sur Version 11.4

  3. JRE/JDK version 1.8

Version since SWT version since when the behavior is seen [3.116.100]

Workaround (or) Additional context

Phillipus commented 1 year ago

Try using a paint listener. Otherwise the image will be tiled (this is how images in Composites are rendered):

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;

public class TestBgImage {

    public static void main(String[] args) {
        final Display display = new Display();
        final Shell shell = new Shell(display, SWT.SHELL_TRIM);
        shell.setBounds(0, 0, 320, 488);

        Composite composite = new Composite(shell, SWT.H_SCROLL);
        composite.setBounds(0, 0, 95, 26);
        ScrollBar horizontalBar = composite.getHorizontalBar();
        if (horizontalBar != null) {
            horizontalBar.setVisible(false);
        }

        Image image = new Image(null, "output.png");

        composite.addPaintListener(e -> e.gc.drawImage(image, 0, 0) );

        shell.open();

        // Set up the event loop.
        while(!shell.isDisposed()) {
            if(!display.readAndDispatch()) {
                // If no more entries in event queue
                display.sleep();
            }
        }
        display.dispose();
    }

}
AsheraCordova commented 1 year ago

I have stretched the image to fit the screen so that they do not tile. If I use SWT.NONE there is no issue.

If I use SWT.BORDER, SWT.V_SCROLL and SWT.H_SCROLL, this issue happens. The image tiles and the sync between platforms is lost.

If we use paint listener, we cannot inherit the background.

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;

public class TestBgImage {

    public static void main(String[] args) {
        final Display display = new Display();
        final Shell shell = new Shell(display, SWT.SHELL_TRIM);
        shell.setBounds(0, 0, 320, 488);
        shell.setBackgroundMode(SWT.INHERIT_FORCE);

        Composite composite = new Composite(shell, SWT.H_SCROLL);
        composite.setBounds(0, 0, 95, 26);
        ScrollBar horizontalBar = composite.getHorizontalBar();
        if (horizontalBar != null) {
            horizontalBar.setVisible(false);
        }

        Label text = new Label(composite, SWT.NONE);
        text.setBounds(0, 0, 30, 26);
        text.setText("aa");
        Image image = new Image(null, "output.png");
//        composite.addPaintListener(e -> e.gc.drawImage(image, 0, 0) );

        composite.setBackgroundImage(image);

        shell.open();

        // Set up the event loop.
        while(!shell.isDisposed()) {
            if(!display.readAndDispatch()) {
                // If no more entries in event queue
                display.sleep();
            }
        }
        display.dispose();
    }

}

I am not able to find a solution where you can have a background image for scroll view, horizontal scroll view and bordered composite and components are embedded in it and the background should display without tiling.

Another issue is that if we the background to the text instead of composite, the same issue happens.

text.setBackgroundImage(image);

It is fine if the style is SWT.NONE and starts tiling in macos for SWT.BORDER, SWT.V_SCROLL and SWT.H_SCROLL.

AsheraCordova commented 1 year ago

Checking the code of Control, may be the patternPhase for the NSColor is not applied properly.

if (imgHeight == -1) {
            NSView contentView = controlView.window().contentView();
            phase = controlView.convertPoint_toView_(phase, contentView);
            phase.y = contentView.bounds().height - phase.y;
        }

Is it because we are using window().contentView. May be we should have used superview.

if (imgHeight == -1) {
            NSView contentView = controlView.superview();
            phase = controlView.convertPoint_toView_(phase, contentView);
            phase.y = contentView.bounds().height - phase.y;
        }