|
16 | 16 |
|
17 | 17 | import java.util.Arrays; |
18 | 18 | import java.util.HashMap; |
| 19 | +import java.util.concurrent.atomic.AtomicReference; |
19 | 20 |
|
20 | 21 | import org.eclipse.core.runtime.IProgressMonitor; |
21 | 22 | import org.eclipse.core.runtime.IStatus; |
|
40 | 41 | import org.eclipse.swt.widgets.Composite; |
41 | 42 | import org.eclipse.swt.widgets.Control; |
42 | 43 | import org.eclipse.swt.widgets.Display; |
| 44 | +import org.eclipse.swt.widgets.Listener; |
43 | 45 | import org.eclipse.swt.widgets.Shell; |
44 | 46 |
|
45 | 47 | /** |
@@ -1086,9 +1088,62 @@ protected static boolean dialogFontIsDefault() { |
1086 | 1088 | @Override |
1087 | 1089 | public void create() { |
1088 | 1090 | super.create(); |
| 1091 | + hookZoomChangeListenerForDefaultSizedDialogs(); |
1089 | 1092 | applyDialogFont(buttonBar); |
1090 | 1093 | } |
1091 | 1094 |
|
| 1095 | + /* |
| 1096 | + * There is no linear relation between font size and containing control size |
| 1097 | + * scaled according to some zoom value. In consequence, text with a scaled font |
| 1098 | + * size may not fit into a control/shell with a size scaled by the same zoom. To |
| 1099 | + * adhere for this in case of Windows using the default computed size, ensure |
| 1100 | + * that on zoom change the new proper size is computed and applied. This will |
| 1101 | + * not affect Windows that have a custom size, either programmatically or |
| 1102 | + * manually applied. |
| 1103 | + */ |
| 1104 | + private void hookZoomChangeListenerForDefaultSizedDialogs() { |
| 1105 | + boolean hasCustomSize = !getShell().getSize().equals(getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true)); |
| 1106 | + boolean isEmpty = getShell().getChildren().length == 0; |
| 1107 | + if (resizeHasOccurred || hasCustomSize || isEmpty || isResizable()) { |
| 1108 | + return; |
| 1109 | + } |
| 1110 | + |
| 1111 | + AtomicReference<Listener> customResizeListener = new AtomicReference<>(); |
| 1112 | + Listener adaptDefaultSizeListener = event -> { |
| 1113 | + Shell shell = getShell(); |
| 1114 | + if (shell == null || shell.isDisposed()) { |
| 1115 | + return; |
| 1116 | + } |
| 1117 | + Point size = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); |
| 1118 | + shell.setSize(size); |
| 1119 | + }; |
| 1120 | + AtomicReference<Listener> zoomChangeListener = new AtomicReference<>(); |
| 1121 | + zoomChangeListener.set(event -> { |
| 1122 | + Shell shell = getShell(); |
| 1123 | + if (shell == null || shell.isDisposed()) { |
| 1124 | + return; |
| 1125 | + } |
| 1126 | + shell.addListener(SWT.Resize, adaptDefaultSizeListener); |
| 1127 | + shell.removeListener(SWT.Resize, customResizeListener.get()); |
| 1128 | + shell.getChildren()[0].removeListener(SWT.ZoomChanged, zoomChangeListener.get()); |
| 1129 | + }); |
| 1130 | + customResizeListener.set(event -> { |
| 1131 | + Shell shell = getShell(); |
| 1132 | + if (shell == null || shell.isDisposed()) { |
| 1133 | + return; |
| 1134 | + } |
| 1135 | + shell.getChildren()[0].removeListener(SWT.ZoomChanged, zoomChangeListener.get()); |
| 1136 | + }); |
| 1137 | + |
| 1138 | + // We need to detect the zoom change event before the resize triggered by the |
| 1139 | + // zoom change happened, which is why we cannot listen to the zoom change at the |
| 1140 | + // shell but must use one of its children |
| 1141 | + getShell().getChildren()[0].addListener(SWT.ZoomChanged, zoomChangeListener.get()); |
| 1142 | + // If custom resize happens before first zoom change, the dialog is custom sized |
| 1143 | + // and should not be auto-resized on zoom change |
| 1144 | + getShell().addListener(SWT.Resize, customResizeListener.get()); |
| 1145 | + } |
| 1146 | + |
1092 | 1147 | /** |
1093 | 1148 | * Get the IDialogBlockedHandler to be used by WizardDialogs and |
1094 | 1149 | * ModalContexts. |
|
0 commit comments